当前位置: 首页 > 后端技术 > Java

Java动态代理

时间:2023-04-01 23:06:38 Java

1。自己实现代理类公共接口BizDemo{voidhelloGirl(Stringname);voidhelloBoy(Stringname);}publicclassBizDemoImplimplementsBizDemo{@OverridepublicvoidhelloGirl(Stringname){System.out.println(name+"helloGirlinBizDemoImpl");}@OverridepublicvoidhelloBoy(Stringname){System.out.println(name+"helloBoyinBizDemoImpl");}}publicclassBizDemoImplProxyimplementsBizDemo{privateBizDemoreal;BizDemoImplProxy(BizDemoreal){this.real=real;}@OverridepublicvoidhelloGirl(Stringname){System.out.println("BizDemoImplProxy代理");this.real.helloGirl(名字);}@OverridepublicvoidhelloBoy(Stringname){System.out.println("BizDemoImplProxy代理");this.real.helloBoy(名字);}}publicstaticvoidmain(String[]args){BizDemodemo=newBizDemoImpl();demo.helloGirl("露西");BizDemodemoProxy=newBizDemoImplProxy(demo);demoProxy.helloGirl("露西");}//在BizDemoImpl2中通过BizDemoImplProxyLucyhelloGirl在BizDemoImplproxy中输出LucyhelloGirl。BizDemoImpl充当代理,看看java中自动生成代理类的效果首先实现一个InvocationHandlerprintln("代理调用。"+args[0]);返回空值;}}下面可以看到,只要有BizDemo的接口,就可以通过java动态代理生成一个类,这个类拥有BizDemo接口的所有方法,并且调用所有方法,都透传给invokeProxyHandler的方法publicstaticvoidmain(String[]args){Class[]inf=newClass[]{BizDemo.class};BizDemod=(BizDemo)Proxy.newProxyInstance(BizDemo.class.getClassLoader(),inf,newProxyHandler());d.helloGirl("javaDynamicProxy");d.helloBoy("javaDynamicProxyboy");}//输出代理invoke.javaDynamicProxyproxyinvoke.javaDynamicProxyboy虽然我们可以让java为我们动态生成一个类,这个类实现了BizDemo接口,但是这样的类并没有太大的实际意义.我们的目的是代理BizDemoImpl。让我们看看我们是如何实现的,让代理具有实际意义。代理BizDemoImpl其实很简单。我们只需要将BizDemoImpl实例插入到ProxyHandler中,并在invoke方法中再次调用它。我们创新创建一个Handler:ProxyHandler1publicclassProxyHandler1implementsInvocationHandler{privateBizDemoreal;publicProxyHandler1(BizDemoreal){this.real=real;}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{System.out.println("proxyinvoke."+args[0]);method.invoke(真正的,args);返回空值;}}publicstaticvoidmain(String[]args){BizDemodemo=newBizDemoImpl();Class[]inf=newClass[]{BizDemo.class};BizDemod=(BizDemo)Proxy.newProxyInstance(BizDemo.class.getClassLoader(),inf,newProxyHandler1(demo));d.helloGirl("javaDynamicProxy");d.helloBoy("javaDynamicProxyboy");}//输出代理invoke.javaDynamicProxyjavaDynamicProxyhelloGirlinBizDemoImplproxyinvoBizDemoImpl中的ke.javaDynamicProxyboyjavaDynamicProxyboyhelloBoy可以看到动态代理生成的类其实是BizDemoImpl实例demo的代理。从上面的例子来看,使用java动态代理是比较复杂的类,需要引入InvocationHandler和java.lang.reflect。Proxy,不过仔细想想还是不错的。首先,无论用户界面有多少方法,最终都会被聚集到InvocationHandler的invoke中。其次,如果项目中需要代理的接口很多,代理类就会成倍增加,维护起来也很困难。java动态代理类图如下。$Proxxy0是java动态生成的类。该类继承了类Proxy实现了BizDemo接口,也就是上面main中的d。d的调用先到$Proxy0,$Proxxy0委托给parent类的Proxy的成员变量InvocationHandler的InvocationHandler实例就是ProxyHandler1实例;ProxyHandler1实例的invoke方法最终调用代理的BizDemoImpl总之,看起来很绕。框架类的代码往往会牺牲直觉来实现通用性和简洁性。3.神秘的动态生成代理类。去文档看看它的神秘面纱publicstaticvoidmain(String[]args){BizDemodemo=newBizDemoImpl();Class[]inf=newClass[]{BizDemo.class};BizDemod=(BizDemo)Proxy.newProxyInstance(BizDemo.class.getClassLoader(),inf,newProxyHandler1(demo));d.helloGirl("javaDynamicProxy");d.helloBoy("javaDynamicProxyboy");//保存动态类到文件byte[]classFile=ProxyGenerator.generateProxyClass("$Proxy0",BizDemoImpl.class.getInterfaces());试试{Filefile=newFile("Proxy0.class");FileOutputStreamout=newFileOutputStream(文件);out.write(类文件);}catch(Exceptione){}|动态类代码如下,动态类的三个要点$Proxy0extendsProxy实现BizDemo,继承Proxy实现BizDemo,所有实现BizDemo接口的方法都委托给h父类Proxy的,是本例是ProxyHandler1实例Proxy的成员h,是抽象接口InvocationHandler,具体类由用户自定义。依赖抽象而不是具体实现类的常见设计思想说明:$Proxy0的0是java动态生成代理类的编号,如果有多个编号自动递增publicfinalclass$Proxy0extendsProxyimplementsBizDemo{privatestaticMethodm1;私有静态方法m4;私有静态方法m2;私有静态方法m3;私有静态方法m0;public$Proxy0(InvocationHandlervar1)throws{super(var1);}publicfinalbooleanequals(Objectvar1)throws{try{return(Boolean)super.h.invoke(this,m1,newObject[]{var1});}catch(RuntimeException|Errorvar3){throwvar3;}catch(Throwablevar4){thrownewUndeclaredThrowableException(var4);}}publicfinalvoidhelloGirl(Stringvar1)throws{try{super.h.invoke(this,m4,newObject[]{var1});}catch(RuntimeException|Errorvar3){throwvar3;}catch(Throwablevar4){thrownewUndeclaredThrowableException(var4);}}公共最终StringtoString()throws{try{return(String)super.h.invoke(this,m2,(Object[])null);}}catch(RuntimeException|Errorvar2){throwvar2;}catch(Throwablevar3){thrownewUndeclaredThrowableException(var3);}}publicfinalvoidhelloBoy(Stringvar1)throws{try{super.h.invoke(this,m3,newObject[]{var1});}catch(RuntimeException|Errorvar3){throwvar3;}catch(Throwablevar4){thrownewUndeclaredThrowableException(var4);}}publicfinalinthashCode()throws{try{return(Integer)super.h.invoke(this,m0,(Object[])null);}catch(RuntimeException|Errorvar2){throwvar2;}catch(Throwablevar3){thrownewUndeclaredThrowableException(var3);}}static{try{m1=Class.forName("java.lang.Object").getMethod("equals",Class.forName("java.lang.Object"));m4=Class.forName("test.BizDemo").getMethod("helloGirl",Class.forName("java.lang.String"));m2=Class.forName("java.lang.Object").getMethod("toString");m3=Class.forName("test.BizDemo").getMethod("helloBoy",Class.forName("java.lang.String"));m0=Class.forName("java.lang.Object").getMethod("hashCode");}catch(NoSuchMethodExceptionvar2){抛出新的NoSuchMethodError(var2.getMessage());}catch(ClassNotFoundExceptionvar3){thrownewNoClassDefFoundError(var3.getMessage());}}}4.生成代理类的老方法publicstaticvoidmain(String[]args){BizDemodemo=newBizDemoImpl();//1.获取代理类的类对象ClassproxyClass=Proxy.getProxyClass(BizDemo.class.getClassLoader(),newClass[]{BizDemo.class});try{//2.获取构造函数反射Constructorcon=proxyClass.getConstructor(InvocationHandler.class);//3。通过反射创建类实例BizDemodemo1=(BizDemo)con.newInstance(newProxyHandler1(demo));demo1.helloGirl("代理类");}catch(Exceptione){e.printStackTrace();}}看源码可以知道Proxy.newProxyInstance其实就是封装了上面的流程5.可能的陷阱publicstaticvoidmain(String[]args){BizDemodemo=newBizDemoImpl();Class[]inf=newClass[]{BizDemo.class};BizDemod=(BizDemo)Proxy.newProxyInstance(BizDemo.class.getClassLoader(),inf,newProxyHandler1(demo));BizDemod1=(BizDemo)Proxy.newProxyInstance(BizDemo.class.getClassLoader(),BizDemoImpl.class.getInterfaces(),newProxyHandler1(demo));BizDemod2=(BizDemo)Proxy.newProxyInstance(BizDemo.class.getClassLoader(),BizDemo.class.getInterfaces(),newProxyHandler1(demo));}d和d1都可以,但是d2会报错,因为BizDemo.class.getInterfaces()返回一个长度为0的Class数组,具体见getInterfaces的接口注解@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{System.out.println("proxyinvoke."+参数[0]);method.invoke(real,args);//method.invoke(proxy,args);//导致递归调用returnnull;}invoke传入的proxy好像没有用到。在ProxyHandler1的invoke方法中,传入的代理是$Proxy0。如果使用method.invoke(proxy,args),会被递归调用,最终导致递归栈溢出。6.参考文档https://www.cnblogs.com/gonja...