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

这次彻底理解了JDK动态代理

时间:2023-03-23 12:13:49 科技观察

动态代理V.S静态代理Proxy类代码是固定的,以后会因为业务越来越大,无法实现AOP编程。这是静态代理无法实现的解耦。如果在web业务下使用,动态代理可以实现数据层和业务层分离的好处是实现非侵入式代码扩展。静态代理模型本身就有很大的问题。如果类方法的数量增加,代理类的代码量会非常大。所以引入动态代理的关键Java实现动态代理的关键:ProxyInvocationHandlerInvocationHandler#invokemethod调用的方法,也就是要执行的方法args方法的参数proxy代理类实例图片JDK动态proxyJDK动态代理模式中有拦截在JDK中,只要实现了InvocationHandler接口的类就是拦截类。拦截器的作用:控制目标对象的目标方法的执行。拦截器的具体运行步骤:1.引入类目标类和一些与扩展方法相关的类2.赋值构造函数给相关对象赋值3.合并逻辑处理在invoke方法中将所有逻辑组合在一起.最后决定是否调用目标方法。以下面的问题为例:谁为代理对象生成JVM。与静态代理不同,我们必须自己创建一个新的代理对象。代理对象实现了什么接口?实现的接口就是目标对象实现的接口。静态代理中代理对象实现的接口。继承图还是一样。代理对象和目标对象都实现了一个公共接口。这是界面。所以Proxy.newProxyInstance()方法返回的类型就是这个接口类型。代理对象的方法体是什么?代理对象的方法体中的内容就是拦截器中invoke方法中的内容。所有代理对象的处理逻辑控制着是否执行目标对象的目标方法。都在这个方法中处理。拦截器中invoke方法中的方法参数是什么时候赋值的?在客户端,当代理对象调用目标方法时,在这个实例中是:proxyObj.business();真正进入的是拦截器中的invoke方法,那么拦截器中的invoke方法中的方法参数就会被赋值。这个为什么叫JDK动态代理,因为动态代理对象是用JDK相关代码生成的。很多同学一直对动态代理一头雾水,因为误解了proxyObj.business();$Proxy0没找到这个proxyObj和Proxy类的联系,一直很好奇最后调用的business()是怎么和invoke()联系起来的?invoke是怎么知道business的存在的?因为大部分同学不知道$Proxy0这个类,看看下面的$Proxy0源码,相信你就能完全理解动态代理了。虽然我们没有显式地调用invoke,但是这个方法被执行了。newProxyInstance方法可以作为突破口。我们看一下Proxy类中newProxyInstance方法的源码:finalSecurityManagersm=System.getSecurityManager();if(sm!=null){checkProxyAccess(Reflection.getCallerClass(),loader,intfs);}/**查找或生成指定代理类*创建代理类$Proxy0*$Proxy0类实现了接口的接口,继承了Proxy类*/Classcl=getProxyClass0(loader,intfs);/**用指定的callhandler调用其构造函数*/try{if(sm!=null){checkNewProxyPermission(Reflection.getCallerClass(),cl);}//形参为InvocationHandler类型的构造函数finalConstructorcons=cl.getConstructor(constructorParams);finalInvocationHandlerih=h;if(!Modifier.isPublic(cl.getModifiers())){AccessController.doPrivileged(newPrivilegedAction(){publicVoidrun(){cons.setAccessible(true);returnull;}});}returncons.newInstance(newObject[]{h});}...什么}Proxy.newProxyInstance做什么?调用方法getProxyClass(loader,interfaces)创建代理$Proxy0类$Proxy0类实现interfaces接口,继承Proxy类实例化$Proxy0,并在构造函数中传入DynamicSubject,然后$Proxy00调用父类Proxy的构造函数,将$Proxy0的源码赋值给h:packagecom.sun.proxy;publicfinalclass$Proxy0extendsProxyimplementsTargetInterface{privatestaticMethodm1;privatestaticMethodm3;privatestaticMethodm2;privatestaticMethodm0;public$Proxy0(InvocationHandlervar1)throws{super(var1);}publicfinalbooleanequals(Object.var1)invocation1kethrows(this{booleanurnthis1){booleanurnthis1))throws{try{ret,newObject[]{var1});}...}publicfinalvoidbusiness()throws{try{super.h.invoke(this,m3,(Object[])null);}...}publicfinalStringtoString()throws{try{return(String)super.h.invoke(this,m2,(Object[])null);}...}publicfinalinthashCode()throws{try{return(Integer)super.h.invoke(this,m0,(Object[])null);}...}static{try{m1=Class.forName("java.lang.Object").getMethod("equals",Class.forName("java局域网g.Object"));m3=Class.forName("com.javaedge.design.pattern.structural.proxy.dynamicproxy.jdkdynamicproxy.TargetInterface").getMethod("business");m2=Class.forName("java.lang.Object").getMethod("toString");m0=Class.forName("java.lang.Object").getMethod("hashCode");}...}}然后将获取到的$Proxy0实例转换为TargetInterface,并将引用赋值给TargetInterface,执行proxyObj.business()时,会调用$Proxy0类中的business()方法,然后在父类Proxy中调用h的invoke()方法即InvocationHandler.invoke()最后提醒Proxy#getProxyClass返回的是Proxy的Class类,不是很多同学说的“代理类的Class类”理所当然!本文转载自微信公众号「JavaEdge」,您可以通过以下二维码关注,转载请联系JavaEdge公众号。