当前位置: 首页 > 科技观察

Java实现代理模式的三种方式

时间:2023-03-13 16:44:22 科技观察

什么是代理模式代理模式是项目中常用的一种设计模式。提供一种间接访问目标对象的方法;即通过代理对象来访问目标对象。这样做的好处是,在不改变原有目标对象的情况下,可以为目标对象增加额外的扩展功能。代理模式分为静态代理、jdk动态代理、cglib动态代理三种实现方式。三种实现方式各有优势和适用场景。1.静态代理代理对象和被代理对象需要实现相同的接口或者继承相同的父类,所以必须定义一个接口或者抽象类。/**代理接口*/publicinterfaceIHello{Stringhi(Stringkey);}/**代理接口实现类*/publicclassHelloImplimplementsIHello{@OverridepublicStringhi(Stringkey){Stringstr="hello:"+键;System.out.println("HelloImpl!"+str);返回海峡;}}/**静态代理类*/publicclassHelloStaticProxyimplementsIHello{privateIHellohello;publicHelloStaticProxy(IHellohello){这个。你好=你好;}@OverridepublicStringhi(Stringkey){System.out.println(">>>staticproxystart");字符串结果=hello.hi(key);System.out.println(">>>静态代理结束");返回结果;}}/**Test*/publicclassDemoTest{publicstaticvoidmain(String[]args){IHellohelloProxy=newHelloStaticProxy(newHelloImpl());helloProxy.hi("世界");}}输出结果:>>>staticproxystartHelloImpl!hello:world>>>staticproxyend2.jdk动态代理jdk动态代理是一种基于接口的代理方式,target对象必须实现接口的原则是利用反射机制动态生成一个匿名类,继承Proxy类,实现被代理的接口。由于Java不支持多重继承,JDK动态代理无法代理该类。/**代理接口*/publicinterfaceIHello{Stringhi(Stringkey);}/**代理接口实现类*/publicclassHelloImplimplementsIHello{@OverridepublicStringhi(Stringkey){Stringstr="hello:"+键;System.out.println("HelloImpl!"+str);返回海峡;}}/**jdk动态代理类*/publicclassJdkProxyimplementsInvocationHandler{privateObjecttarget;publicJdkProxy(Objecttarget){this.target=target;}/***获取代理接口的实例对象**@param*@return*/publicTgetProxy(){return(T)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),这个);}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{System.out.println(">>>JdkProxystart");对象结果=方法。调用(目标,参数);系统。出去。println(">>>JdkProxy结束");返回结果;}}/**Test*/publicclassDemo2Test{publicstaticvoidmain(String[]args){JdkProxyproxy=newJdkProxy(newHelloImpl());IHellohelloProxy=proxy.getProxy();helloProxy.hi("jdk代理!");}}输出结果:>>>JdkProxystartHelloImpl!hello:jdkproxy!>>>JdkProxyend3.cglib动态代理目标对象不需要实现接口,不能代理final类。其原理是动态生成类继承对象对象。使用cglib必须引入相应的jar包。cglibcglib3.2.7/**目标类*/publicclassHelloImpl{publicStringhi(Stringkey){Stringstr="你好:"+key;System.out.println("HelloImpl!"+str);返回海峡;}}/**cglib代理类*/publicclassCglibProxyimplementsInvocationHandler{privateObjecttarget;/***获取代理接口的实例对象*/publicTgetProxy(){//1创建增强器对象Enhancere=newEnhancer();//2设置增强器的类加载器e.setClassLoader(target.getClass().getClassLoader());//3设置代理对象的父类类型e.setSuperclass(target.getClass());//4设置回调函数e.setCallback(this);//5创建代理对象return(T)e.create();}publicCglibProxy(Objecttarget){this.target=target;}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)抛出Throwable{System.out.println(">>>cglib启动");对象obj=method.invoke(target,args);System.out.println(">>>cglib结束");返回对象;}}/**Test*/publicclassDemo3Test{publicstaticvoidmain(String[]args){HelloImplhello=newHelloImpl();CglibProxycglibProxy=newCglibProxy(你好)??;HelloImplproxy=cglibProxy.getProxy();proxy.hi("cglib");}}输出结果:>>>cglibstartHelloImpl!hello:cglib>>>cglibend4.总结一下静态代理,代理类一定很明确,所以不能通用,但是也是jdk动态代理效率最高的,必须是基于接口代理,这有一定的局限性;动态生成的字节码文件可用于一般业务(性能日志等)。cglig动态代理也是动态生成字节码文件,生成的代理类继承目标对象。springaop默认的代理策略是:如果目标对象实现了接口,则使用jdk动态代理,否则使用cglib代理。jdk8之后,jdk动态代理比cglib代理更高效。