首页IT科技jdk动态代理 cglib(Java JDK Proxy和CGLib动态代理示例讲解)

jdk动态代理 cglib(Java JDK Proxy和CGLib动态代理示例讲解)

时间2025-06-15 00:45:26分类IT科技浏览4183
导读:简介 代理模式在Java中有很多应用场景,而代理又分静态代码和动态代理。静态代理是编写、编译或加载时织入代码实现,而动态代理则在运行时实现。简单而言,静态代理是在运行前就已经存在,而动态代理则在运行时才存在的。而常用的动态代理有两种实现:...

简介

代理模式在Java中有很多应用场景            ,而代理又分静态代码和动态代理            。静态代理是编写            、编译或加载时织入代码实现                   ,而动态代理则在运行时实现                  。简单而言      ,静态代理是在运行前就已经存在            ,而动态代理则在运行时才存在的       。而常用的动态代理有两种实现:

JDK Proxy: JDK Proxy是JDK自带的                   ,不需要引入外部库      ,通过实现接口进行代理; CGLib: CGLib是引入第三方库      ,通过ASM技术来实现字节码的生成;通过继承的方式来实现      。

现在我们来通过代码分别展示一下两种方式                  。

JDK Proxy

JDK Proxy是通过实现接口来实现代理的                   ,我们先定义一个接口:

public interface Flyable { String fly(String route); }

接着有一个实现类:

public class Bird implements Flyable { @Override public String fly(String route) { System.out.println("Route: " + route); return route; } }

然后我们需要定义一个InvocationHandler来改动方法的逻辑            ,就是目标被代理后有什么不同:

public class FlyableInvocation implements InvocationHandler { private final Flyable target; public FlyableInvocation(Flyable target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long start = System.nanoTime(); System.out.println(target + ": ===JDK proxy==="); Object result = method.invoke(this.target, args); System.out.println(target + ": ===JDK proxy==="); long end = System.nanoTime(); System.out.println("Executing time: " + (end - start) + " ns"); return result; } }

这里我们在方法调用前后加了日志      ,同时也计算了一下方法的执行时间             。

最终在调用的时候如下:

public class JDKDynamicProxy { public static void main(String[] args) { ClassLoader classLoader = JDKDynamicProxy.class.getClassLoader(); Class<?>[] interfaces = Bird.class.getInterfaces(); Bird bird = new Bird(); Flyable flyable = (Flyable) Proxy.newProxyInstance(classLoader, interfaces, new FlyableInvocation(bird)); flyable.fly("Go to pkslow.com"); } }

通过Proxy.newProxyInstance方法会生成一个代理的实例                   ,执行这个实例的方法            ,而原有实例bird被代理了      。

执行结果如下:

com.pkslow.basic.jdk.Bird@3551a94: ===JDK proxy=== Route: Go to pkslow.com com.pkslow.basic.jdk.Bird@3551a94: ===JDK proxy=== Executing time: 18195736 ns

查看代理类

我们还可以查看生成的代理类,可以通过添加VM参数:

# JDK 8 -Dsum.misc.ProxyGenerator.saveGeneratedFiles=true # JDK 11 -Djdk.proxy.ProxyGenerator.saveGeneratedFiles=true

当然                   ,也可以在Java代码中设置系统属性来实现                  。

设置完成                   ,再执行程序,就会生成代理类的.class文件             。

CGLib

CGLib是通过继承来实现的            ,我们先来定义一个类:

public class Animal { public String talk(String str) { System.out.println("Talking: " + str); return str; } }

然后定义一个Interceptor                   ,这个类的作用就是生成代理实例      ,且定义如何改变目标方法的执行:

public class CGLibProxy<T> implements MethodInterceptor { private T target; public T getInstance(T target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); enhancer.setCallback(this); return (T) enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { long start = System.nanoTime(); System.out.println(target + ": ===CGLib proxy==="); Object result = methodProxy.invoke(this.target, args); System.out.println(target + ": ===CGLib proxy==="); long end = System.nanoTime(); System.out.println("Executing time: " + (end - start) + " ns"); return result; } }

这里同样是在方法前后加了日志            ,同时记录时长。

调用如下:

public class CGLibDynamicProxy { public static void main(String[] args) { System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/larry/IdeaProjects/pkslow-samples/java-basic/jdk-cglib-proxy/target/cglib_proxy_classes"); CGLibProxy<Animal> cgLibProxy = new CGLibProxy<>(); Animal animal = cgLibProxy.getInstance(new Animal()); animal.talk("Hi, pkslow"); } }

这里设置系统属性是为了把生成的代理类输出到.class文件中                   ,方便学习查看                  。

执行结果如下:

com.pkslow.basic.cglib.Animal@57855c9a: ===CGLib proxy=== Talking: Hi, pkslow com.pkslow.basic.cglib.Animal@57855c9a: ===CGLib proxy=== Executing time: 28396871 ns

总结

JDK Proxy本质上使用的是反射的机制      ,而CGLib使用的是ASM      ,CGLib速度会更好                   。但它们都不支持final的类和方法                   ,因为通过接口和继承都无法改变final方法。

代码请看GitHub: https://github.com/LarryDpk/pkslow-samples

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
phpcms教程(phpcms v9如何安装) 弹性云服务器是虚拟机吗怎么用(弹性云服务器租用可以干什么)