这个就是静态代理,兄弟们应该已经发现了它的缺点,只能指定自己想要进行代理的类,而不能对所有的类进行代理,扩展性太差,所以引出了动态代理
谈到动态代理,脑子里第一个出现的肯定就是Java动态代理了。我们先来聊一下Java动态代理。
先来看一个动态代理的案例
NaiKenaiKe=newNaiKe();Shoesshoes=(Shoes)Proxy.newProxyInstance(NaiKe.class.getClassLoader(),newClass[]{Shoes.class},newInvocationHandler(){@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{System.out.println("begintimer:"+System.currentTimeMillis());method.invoke(naiKe,args);System.out.println("aftertimer:"+System.currentTimeMillis());returnnull;}});shoes.run();我们看一下动态代理的源码。
我们可以通过以下方式让JVM将动态生成的代理类保存到我们的项目中
生成的代理类如下:
finalclass$Proxy0extendsProxyimplementsShoes{privatestaticMethodm1;privatestaticMethodm3;privatestaticMethodm2;privatestaticMethodm0;public$Proxy0(InvocationHandlervar1)throws{super(var1);}publicfinalbooleanequals(Objectvar1)throws{}publicfinalvoidrun()throws{try{super.h.invoke(this,m3,(Object[])null);}catch(RuntimeException|Errorvar2){throwvar2;}catch(Throwablevar3){thrownewUndeclaredThrowableException(var3);}}publicfinalStringtoString()throws{}publicfinalinthashCode()throws{}static{try{m1=Class.forName("java.lang.Object").getMethod("equals",Class.forName("java.lang.Object"));m3=Class.forName("desgin.proxy.Shoes").getMethod("run");m2=Class.forName("java.lang.Object").getMethod("toString");m0=Class.forName("java.lang.Object").getMethod("hashCode");}catch(NoSuchMethodExceptionvar2){thrownewNoSuchMethodError(var2.getMessage());}catch(ClassNotFoundExceptionvar3){thrownewNoClassDefFoundError(var3.getMessage());}}}从这个类的结构中,我们可以看出很多的东西
上面两个也是动态代理的原理了。我们来仔细看一下我们的run()方法,也就是我们代理对象要实现的接口
publicfinalvoidrun()throws{try{super.h.invoke(this,m3,(Object[])null);}catch(RuntimeException|Errorvar2){throwvar2;}catch(Throwablevar3){thrownewUndeclaredThrowableException(var3);}}这个就是动态代理的全部实现过程
还有一个非常牛逼的点,它怎么生成的这个代理类。来看一下代理的全过程
图中的ASM就是为我们动态生成一个代理类的工具,它直接操作了Class字节码的二进制,然后创建了一个代理类,返回给我们。
Java动态代理就聊到这里了。下面看一看CGLIb和AOP
弥补了Java动态代理的不足,CGLIB动态代理可以代理类。它直接创建了一个被代理对象的子类,实现了对其的代理过程。我们来看一下它的代理过程
//打印生成的代理对象,放置于当前项目下System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,".");//创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数Enhancerenhancer=newEnhancer();//设置目标类的字节码文件enhancer.setSuperclass(Tank.class);//设置回调函数enhancer.setCallback(newMethodInterceptor(){@OverridepublicObjectintercept(Objecto,Methodmethod,Object[]objects,MethodProxymethodProxy)throwsThrowable{methodProxy.invokeSuper(o,objects);returnnull;}});//这里的creat方法就是正式创建代理类TankproxyDog=(Tank)enhancer.create();//调用代理类的eat方法proxyDog.tank();还是和Java动态代理相似,传入一个需要代理的Class,设置代理的回调函数。然后调用create创建一个代理对象,调用代理对象的方法。
代理第一行可以输出代理对象,会生成三个代理对象。
查看中间那个,可以看到我们被代理对象的方法
publicclassTank$$EnhancerByCGLIB$$a4ec679aextendsTankimplementsFactory{//构造方法publicTank$$EnhancerByCGLIB$$a4ec679a(){CGLIB$BIND_CALLBACKS(this);}//被代理方法finalvoidtank(){MethodInterceptorvar10000=this.CGLIB$CALLBACK_0;if(var10000==null){CGLIB$BIND_CALLBACKS(this);var10000=this.CGLIB$CALLBACK_0;}if(var10000!=null){//调用增强的方法var10000.intercept(this,CGLIB$tank$0$Method,CGLIB$emptyArgs,CGLIB$tank$0$Proxy);}else{super.tank();}}}在之前的CGLIB动态代理实现中,我们看到了拦截的回调中传入了四个参数,从上面的源码中可以看到对应参数的作用。
我们可以看一下superinvoke的源码
publicObjectinvokeSuper(Objectobj,Object[]args)throwsThrowable{try{this.init();MethodProxy.FastClassInfofci=this.fastClassInfo;returnfci.f2.invoke(fci.i2,obj,args);}catch(InvocationTargetExceptionvar4){throwvar4.getTargetException();}}privatestaticclassFastClassInfo{FastClassf1;FastClassf2;inti1;inti2;privateFastClassInfo(){}}一个图理解CgLib动态代理过程
写了这么多,感觉对于代理设计模式讲解的篇幅不是很大,而是着重讲解了动态代理的实现方式。总的而言,代理设计模式与我们日常生活非常的接近,生活中的事物几乎都在被代理,所以这个设计模式应该很好懂,所以着重讲解了动态代理的实现方式。