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

JavaJDKProxy和CGLib动态代理示例讲解

时间:2023-04-01 21:43:03 Java

简介代理模式在Java中有很多应用场景,代理分为静态代码和动态代理。静态代理是在编写、编译或加载时通过编织代码实现的,而动态代理是在运行时实现的。简单的说,静态代理在运行前就存在,而动态代理只在运行时存在。常用的动态代理实现有两种:JDKProxy:JDKProxy是JDK自带的,不需要引入外部库,通过实现接口来实现代理;CGLib:CGLib引入第三方库,通过ASM技术实现字节码的生成;通过继承的方式来实现。下面通过代码分别展示这两种方法。JDKProxyJDKProxy通过实现接口来实现代理。我们先定义一个接口:publicinterfaceFlyable{Stringfly(Stringroute);}然后是一个实现类:publicclassBirdimplementsFlyable{@OverridepublicStringfly(Stringroute){System.out.println("Route:"+路线);返回路线;}}然后我们需要定义一个InvocationHandler来改变方法的逻辑,也就是target被代理后有什么不同:publicclassFlyableInvocationimplementsInvocationHandler{publicFlyableInvocation(Flyabletarget){this.target=target;}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{longstart=System.nanoTime();系统输出。println(target+":===JDKproxy===");对象结果=method.invoke(this.target,args);System.out.println(target+":===JDKproxy===");长端=System.nanoTime();System.out.println("执行时间:"+(end-start)+"ns");返回结果;}}这里我们在方法调用前后添加了日志,同时也计算了方法的执行时间。最后调用方法时如下:类[]接口=Bird.class.getInterfaces();鸟鸟=新鸟();Flyableflyable=(Flyable)Proxy.newProxyInstance(classLoader,interfaces,newFlyableInvocation(bird));flyable.fly("转到pkslow.com");}}通过Proxy.newProxyInstance方法,会生成一个代理实例,执行这个实例的方法,代理原实例bird。执行结果如下:com.pkslow.basic.jdk.Bird@3551a94:===JDKproxy===路由:转到pkslow.com.pkslow.basic.jdk.Bird@3551a94:===JDKproxy===执行时间:18195736ns查看代理类我们也可以通过添加VM参数查看生成的代理类:#JDK8-Dsum.misc.ProxyGenerator.saveGeneratedFiles=true#JDK11-Djdk.proxy.ProxyGenerator.saveGeneratedFiles=trueof当然,也可以通过在Java代码中设置系统属性来实现。设置完成并执行程序后,会生成代理类的.class文件。CGLibCGLib是通过继承实现的,我们先定义一个类:publicclassAnimal{publicStringtalk(Stringstr){System.out.println("Talking:"+str);返回海峡;}}然后定义一个Interceptor,这个类的作用是生成一个代理实例,定义如何改变目标方法的执行:publicclassCGLibProxyimplementsMethodInterceptor{publicTgetInstance(Ttarget){this.target=target;增强器enhancer=newEnhancer();enhancer.setSuperclass(this.target.getClass());enhancer.setCallback(这个);返回(T)enhancer.create();}@OverridepublicObjectintercept(Objecto,Methodmethod,Object[]args,MethodProxymethodProxy)throwsThrowable{longstart=System.nanoTime();System.out.println(target+":===CGLibproxy===");对象结果=methodProxy.invoke(this.target,args);System.out.println(target+":===CGLibproxy===");长端=System.nanoTime();系统输出文件rintln("执行时间:"+(end-start)+"ns");返回结果;}}这里在方法前后也添加了日志,调用记录时长如下:拉里/IdeaProjects/pkslow-samples/java-basic/jdk-cglib-proxy/target/cglib_proxy_classes");CGLibProxy<动物>cgLibProxy=newCGLibProxy<>();动物animal=cgLibProxy.getInstance(newAnimal());animal.talk("嗨,pkslow");}}这里设置系统属性,将生成的代理类输出到.class文件中,方便学习Check。执行结果如下:com.pkslow.basic.cglib.Animal@57855c9a:===CGLibproxy===Talking:Hi,pkslowcom.pkslow.basic.cglib.Animal@57855c9a:===CGLibproxy===Executingtime:28396871ns总结JDKProxy本质上是使用了反射机制,而CGLib使用的是ASM,CGLib的速度会好一些。但是它们都不支持final类和方法,因为final方法不能通过接口和继承来改变。代码请查看GitHub:https://github.com/LarryDpk/p...