java动态代理解析

📅 发布时间:2026/7/8 14:38:32 👁️ 浏览次数:
java动态代理解析
动态代理是 Java 中一种非常重要的技术它允许我们在程序运行时动态地生成代理类并且可以在不修改目标类的情况下改变其行为。Java 提供了两种主要的动态代理方式JDK 动态代理和 CGLIB 动态代理。本文将分别介绍这两种方式并附上相应的代码分析以及比较他们见的区别。一、动态代理的概念动态代理是指在程序运行时通过某种方式生成一个实现了特定接口的代理对象。在 Java 中动态代理主要用于实现一些横切关注点如事务、日志、性能监控等的功能而不需要修改原有的业务逻辑代码。二、JDK 动态代理JDK 动态代理是基于 Java 反射机制实现的它要求目标对象实现至少一个接口。JDK 动态代理通过java.lang.reflect.Proxy类和InvocationHandler接口来实现。1. JDK 动态代理的原理JDK 动态代理生成的代理类是由 JVM 在运行时创建的它继承了Proxy类并实现了目标类的接口。在代理类中所有方法的调用都会被转发到InvocationHandler的invoke方法。2. JDK 动态代理的使用代码示例首先定义一个接口和实现类// 定义一个接口 public interface HelloService { void sayHello(String name); } // HelloService 的实现类 public class HelloServiceImpl implements HelloService { Override public void sayHello(String name) { System.out.println(Hello, name); } }然后创建InvocationHandler实现类import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { this.target target; } Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(被代理方法执行前逻辑 method.getName()); Object result method.invoke(target, args); // 调用目标方法 System.out.println(被代理方法执行后逻辑 method.getName()); return result; } }接下来创建代理对象import java.lang.reflect.Proxy; public class ProxyDemo { public static void main(String[] args) { // 目标对象 HelloService helloService new HelloServiceImpl(); // 创建代理对象 HelloService proxy (HelloService) Proxy.newProxyInstance( helloService.getClass().getClassLoader(), helloService.getClass().getInterfaces(), new MyInvocationHandler(helloService) ); // 调用代理方法 proxy.sayHello(World); } }输出结果被代理方法执行前逻辑 sayHello Hello, World 被代理方法执行后逻辑 sayHello3. JDK 动态代理的特点只能对实现了接口的类生成代理。在运行时动态创建代理类透明地将方法调用转发给InvocationHandler。使用反射机制调用方法因此性能相对较低。4.特别提醒jdk生成的代理类在字节码里已经继承了Proxy类java为单继承所以只能通过实现接口的方式来生成代理类。三、CGLIB 动态代理CGLIBCode Generation Library是一个功能强大的高性能的代码生成库。与 JDK 动态代理不同CGLIB 动态代理不要求目标对象实现接口。它通过继承目标类并重写方法来创建代理对象。1. CGLIB 动态代理的原理CGLIB 通过字节码技术生成目标类的子类并重写其中的方法。CGLIB 动态代理的实现类通过继承目标类并重写目标类的方法来实现代理功能。2. CGLIB 动态代理的使用代码示例首先定义一个目标类public class HelloService { public void sayHello(String name) { System.out.println(Hello, name); } }然后创建 CGLIB 的代理类import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CglibProxyDemo { public static void main(String[] args) { // 创建目标对象 HelloService helloService new HelloService(); // 创建 Enhancer 对象 Enhancer enhancer new Enhancer(); enhancer.setSuperclass(HelloService.class); enhancer.setCallback(new MethodInterceptor() { Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println(被代理方法执行前逻辑 method.getName()); Object result proxy.invokeSuper(obj, args); // 调用父类方法 System.out.println(被代理方法执行后逻辑 method.getName()); return result; } }); // 创建代理对象 HelloService proxy (HelloService) enhancer.create(); // 调用代理方法 proxy.sayHello(World); } }输出结果被代理方法执行前逻辑 sayHello Hello, World 被代理方法执行后逻辑 sayHello3. CGLIB 动态代理的特点不要求目标对象实现接口。通过继承目标类并重写方法来实现代理。性能相对较好比 JDK 动态代理更为高效。不能代理final类和final方法。四、JDK 动态代理与 CGLIB 的比较特性JDK 动态代理CGLIB 动态代理代理方式基于接口实现基于继承实现是否要求接口必须有接口不要求目标类有接口代理对象类型代理类实现目标接口代理类是目标类的子类性能较差使用反射相对较好使用字节码生成代理目标对象类型只能代理接口的实现类可以代理任何类代理限制无法代理没有实现接口的类不能代理final类和方法五、Spring 框架中的使用在 Spring 中当使用 AOP 时框架会根据目标对象是否实现了接口来选择使用 JDK 动态代理还是 CGLIB 代理。如果目标类实现了接口Spring 会使用 JDK 动态代理如果目标类没有实现接口Spring 会自动使用 CGLIB 动态代理这时 Spring 会通过继承目标类并重写方法来生成代理对象。