代理模式的目的是在不修改原有类方法设计的情况下,增强方法行为。为了更好地理解,让我们来看一个实际场景。在我们的业务场景中,往往会有限流的需求。正常的操作是在需要限制的接口代码之前加上判断调用次数的代码。但是,每一个需要用这种方式限制的方法都需要添加。更不用说繁重的工作了。一方面不易维护,无法清楚知道各个接口的限流值。另一方面,限流代码和业务代码叠在一起,也影响代码阅读。解决办法就是做一套统一的限流。一般好点的会有专门的接口限流平台,配置对应的接口名称,设置限流值,直接限流。实现方法可以使用动态代理。原接口的实现没有修改,只是接口增强了。动态代理的好处是实现非侵入式的代码扩展和方法增强;它允许您在不修改源代码的情况下增强某些方法;你可以在方法之前和之后做任何你想做的事情(即使不去执行这个方法)。既然静剂有动,就必有静。让我们谈谈区别。static:最大的区别是static是在编译时确定的。在程序运行之前,代理类的.class文件已经存在。代理类是什么,代理类的实现方法。举个栗子:我现在有一个接口,可以将Json字符串解析成Object对象。接口如下:publicinterfaceIProvider{ObjectgetData(Stringjson);}接口的实现类如下:publicclassSimpleProviderimplementsIProvider{@OverridepublicObjectgetData(Stringjson){//解析json到数据returnparseJson(json);}现在有一个需要限制getData方法的流量,指定使用静态代理的方式。需求很简单,直接贴出来:publicclassProviderProxyimplementsIProvider{//holdsareferencetoaproxiedobject(SimpleProviderhere)IProvideriProvider;publicStaticProviderProxy(IProvideriProvider){this.iProvider=iProvider;}@OverridepublicObjectgetData(Stringjson){//做限流检查if(callSpeed>flowLimt){//限流throwFlowLimitException();}Objectobject=iProvider.getData(json);returnobject;}}//mainpublicstaticvoidmain(String[]args){IProviderprovider=newProviderProxy(newSimpleProvider());provider.getData("{\"data\":{}}");}这是静态代理,代理类(ProviderProxy)实现了与需要方法增强的代理类(SimpleProvider)相同的接口(IProvider),增强了方法的具体实现,这里是限流检查。DynamicProxyJavaDynamicProxy动态代理类:程序运行时,通过反射机制动态生成。动态代理类通常代理接口下的所有类。static一般指定一个类代理。动态代理事先不知道要代理什么,只能在运行时确定。静态是在编译时确定的。仍然以IProvider接口为例,同样需要对SimpleProvider进行增强,如下:getClass().getClassLoader(),target.getClass().getInterfaces(),this);}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{//limitflowLimit(args);Objectobj=method.invoke(target,args);//打印日志logger.info("printlog...");returnobj;}}//mainpublicstaticvoidmain(String[]args){ProviderHandlerproviderHandler=newProviderHandler();IProvideriProvider=(IProvider)providerHandler.bind(newSimpleProvider());iProvider.getData("weibo.data");}这里一共有三个对象:SimpleProvider对象,我们称之为代理对象ProviderHandler对象,我们称之为执行者对象Proxy对象(通过在ProviderHandler绑定方法。对象生成dbynewProxyInstance)我们称它为代理对象。这三个对象之间是什么关系?Proxy是真正的代理类,SimpleProvider是被代理类,ProviderHandler是执行方法增强的执行者。为了增强SimpleProvider(代理对象)的getData方法,使用Proxy对象来代理代理对象的执行。Proxy不亲自做这件事,而是交给执行者对象ProviderHandler来实现添加的目录并执行调用。以前的电流限制检查。它是如何实际实施的?newProxyInstance源码publicstaticObjectnewProxyInstance(ClassLoaderloader,Class>[]interfaces,InvocationHandlerh)throwsIllegalArgumentException{//对InvocationhandlerObjects.requireNonNull(h)做null判断;//复制[IProviderinterface]finalClass>[]intfs=interfaces.clone();//根据IProvider的类加载器IProvider接口生成Proxy类,关键:根据类加载器和接口对象在JVM缓存中生成一个类对象Class>cl=getProxyClass0(loader,intfs);//获取构造函数finalConstructor>cons=cl.getConstructor(constructorParams);//保存InvocationHandler的引用finalInvocationHandlerih=h;//通过构造函数实例化Proxy代理对象returncons.newInstance(newObject[]{h});}代码注释写的很清楚。到这里大家可能会疑惑,生成的Proxy对象是怎么调用executor的invoke函数的。这个地方使用这段代码将Proxy0的类字节码输出到一个文件中。byte[]classFile=ProxyGenerator.generateProxyClass("$Proxy0",WeiboProvider.class.getInterfaces());Stringpath="C:**/IdeaProjects/study/out/production/study/SimpleProxy.class";try(FileOutputStreamfos=newFileOutputStream(path)){fos.write(classFile);fos.flush();System.out.println("代理类文件写入成功");}catch(Exceptione){System.out.println("写入文件错误");}反编译Proxy0如下://Proxy0是动态生成的类,继承自Proxy,实现了IProvider接口。var1);}publicfinalbooleanequals(Objectvar1)throws{try{return((Boolean)super.h.invoke(this,m1,newObject[]{var1})).booleanValue();}catch(RuntimeException|Errorvar3){throwvar3;}catch(Throwablevar4){thrownewUndeclaredThrowableException(var4);}}publicfinalStringtoString()throws{try{return(String)super.h.invoke(this,m2,(Object[])null);}catch(RuntimeException|Errorvar2){throwvar2;}catch(Throwablevar3){thrownewUndeclaredThrowableException(var3);}}publicfinalStringgetData(Stringvar1)throws{try{//m3就是IProvider接口的getData方法//super.h是父类java.lang.reflect.Proxy的属性InvocationHandlerreturn(String)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)).intValue();}catch(RuntimeException|Errorvar2){throwvar2;}catch(Throwablevar3){thrownewUndeclaredThrowableException(var3);}}static{try{m1=Class.forName("java.lang.Object").getMethod("equals",newClass[]{Class.forName("java.lang.Object")});m2=Class.forName("java.lang.Object").getMethod("toString",newClass[0]);//m3就是IProvider接口的getData方法m3=Class.forName("aop.IProvider").getMethod("获取数据",newClass[]{Class.forName("java.lang.String")});m0=Class.forName("java.lang.Object").getMethod("hashCode",newClass[0]);}catch(NoSuchMethodExceptionvar2){thrownewNoSuchMethodError(var2.getMessage());}catch(ClassNotFoundExceptionvar3){thrownewNoClassDefFoundError(var3.getMessage());}}}重点是return(String)super.h.invoke(this,m3,newObject[]{var1});代码$Proxy0继承了Proxy类,实现了IProvider接口,所以也有getData()函数,getData函数调用执行器InvocationHandler的invoke方法,m3是通过反射得到的Method对象,所以看getData调用调用通过。三个参数,第一个是Proxy对象,第二个是getData方法对象,第三个是参数。总结一下:动态代理的本质就是生成一个继承Proxy并实现代理接口(IProvider)的类——Proxy0。Proxy0持有一个InvocationHandler的实例,而InvocationHandler持有一个SimpleProvider的实例。Proxy0调用接口的getData方法时,先传递给InvocationHandler,再将InvocationHandler传递给SimpleProvider实例。动态代理其实就是帮我们直接在JVM内存中重新生成代理类class和对应的类对象,然后通过执行器InvocationHandler调用代理对象SimpleProvider。SpringAOP中的代理Spring代理实际上封装了JDK动态代理和CGLIB代理,并引入了AOP的概念,在AspectJ中引入了一些注解:@pointCut@After等。publicAopProxycreateAopProxy(AdvisedSupportconfig)throwsAopConfigException{if(config.isOptimize()||config.isProxyTargetClass()||hasNoUserSuppliedProxyInterfaces(config)){Class>targetClass=config.getTargetClass();if(targetClass==null){thrownewAopConfigException("TargetSourcecannotdeterminetargetclass:"+"Eitheraninterfaceortargetisrequiredforproxycreation.");}//如果是接口,使用jdk代理if(targetClass.isInterface()||Proxy.isProxyClass(targetClass)){returnnewJdkDynamicAopProxy(config);}//否则使用ProxyAopnesisCglibreturnisCglibreturny(配置);}else{returnnewJdkDynamicAopProxy(配置);}}
