Loading

动态代理的实现原理

CGLIB(Code Generation Library)动态代理的实现原理基于字节码生成技术继承机制,其核心在于运行时生成目标类的子类,通过方法重写实现代理逻辑。以下是具体实现原理和示例的详细说明:


一、核心实现机制

  1. 子类继承
    CGLIB通过ASM框架在内存中生成目标类的子类,代理类继承目标类并重写所有非final方法。例如,若目标类是UserService,生成的代理类结构类似UserService$$EnhancerByCGLIB$$xxx,并重写addUser()方法。

  2. 方法拦截
    代理类重写的方法会调用MethodInterceptor.intercept()方法,开发者可在该方法中插入增强逻辑(如日志、事务等)。例如:

    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) {
        // 前置增强
        Object result = proxy.invokeSuper(obj, args); // 调用父类(目标类)的原始方法
        // 后置增强
        return result;
    }
    
  3. FastClass优化
    CGLIB生成FastClass类,通过方法索引直接调用目标方法,避免反射带来的性能损耗。例如,代理类会生成两个FastClass文件,分别对应目标类和代理类的方法索引。


二、为何调用原方法会变成代理方法?

以示例说明:

  1. 原始类定义

    public class Coder {
        public void work() { System.out.println("认真写bug..."); }
    }
    
  2. 生成代理类
    CGLIB生成子类Coder$$EnhancerByCGLIB$$xxx,并重写work()方法:

    public class Coder$$EnhancerByCGLIB$$xxx extends Coder {
        private MethodInterceptor interceptor;
        
        public void work() {
            interceptor.intercept(this, 
                MethodProxy.create(Coder.class, "work"), 
                new Object[0], 
                super.work);
        }
    }
    
  3. 调用流程
    当用户调用proxy.work()时:

    • 步骤1:实际调用的是代理类Coder$$EnhancerByCGLIB$$xxxwork()方法。
    • 步骤2:代理类方法内部调用MethodInterceptor.intercept(),执行增强逻辑。
    • 步骤3:通过proxy.invokeSuper()调用父类(即原始Coder类的work()方法)。

三、具体实现示例

  1. 目标类与拦截器定义

    public class Service {
        public void process() { System.out.println("业务逻辑"); }
    }
    
    public class LogInterceptor implements MethodInterceptor {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) {
            System.out.println("前置日志");
            Object result = proxy.invokeSuper(obj, args); // 调用父类方法
            System.out.println("后置日志");
            return result;
        }
    }
    
  2. 生成代理对象

    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(Service.class);  // 设置父类为目标类
    enhancer.setCallback(new LogInterceptor()); // 设置方法拦截器
    Service proxy = (Service) enhancer.create(); // 生成代理对象
    
  3. 调用代理方法

    proxy.process(); 
    // 输出:
    // 前置日志
    // 业务逻辑
    // 后置日志
    

四、关键注意事项

  1. final方法无法代理
    CGLIB通过继承实现代理,final方法无法被重写,因此无法代理。

  2. 构造函数限制
    代理类默认调用目标类的无参构造函数,若目标类没有无参构造器,需通过Enhancer.create(Class[], Object[])指定参数。

  3. 性能优化
    FastClass机制通过方法索引直接调用目标方法,相比JDK动态代理的反射调用,执行效率更高。


五、与JDK动态代理的本质区别

维度 CGLIB动态代理 JDK动态代理
实现方式 继承目标类,生成子类 实现接口,生成接口代理类
目标要求 可代理普通类,无需接口 必须实现至少一个接口
方法覆盖 重写非final方法 实现接口方法
性能 初始生成慢,执行快(FastClass优化) 初始生成快,执行慢(反射调用)
适用场景 复杂类继承结构、无接口的类 简单接口代理、轻量级场景

总结

CGLIB动态代理通过运行时生成目标类的子类,重写方法并插入拦截逻辑,使得调用原方法时实际执行的是代理类的增强逻辑。其核心依赖字节码生成技术(ASM)和MethodInterceptor拦截器机制,适用于需要代理普通类或复杂继承结构的场景。

posted @ 2025-05-14 16:12  我不想学编丿程  阅读(73)  评论(0)    收藏  举报