Cglib代理如何生成的及工作原理

本文深入探讨了CGLib在SpringBoot中的代理实现方式,分析了其生成代理对象的过程,包括检查目标类的final方法、创建增强器、配置回调规则等步骤。CGLib通过继承目标类并复写非final方法来实现代理,利用MethodInterceptor接口进行方法拦截。当调用代理对象的方法时,会执行拦截器逻辑,从而实现AOP的功能。此外,文章还对比了CGLib与JDK代理的区别。

Cglib是一个高效的动态代理方式,并且在SpringBoot中默认的代理实现方式。

本片文章会分析Cglib是如何生成代理对象、代理对象如何执行相应的目标函数、及和jdk代理有什么区别。validatedClasses 是静态容器,是对在系统中所有通过cglib创建的目标对象中是否有final method的检查。因为Cglib代理在继承目标对象时要复写所有函数,不可以复写final修饰的函数。

在构建代理对象时通过通知规则来配置。这个通知规则包含了通知器和通知方法。

创建代理对象的流程就在此:


@Override

public Object getProxy(@Nullable ClassLoader classLoader) {

   try {
    
        // 取到通知规则中要被代理的目标对象的 Class对象,由于要继承所以不能为空

      Class<?> rootClass = this.advised.getTargetClass();

      Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");


      Class<?> proxySuperClass = rootClass;

        // 如果目标对象是一个Cglib的对象,会去拿它的父类对象,这个对象一定是真正的目标对象

      if (ClassUtils.isCglibProxyClass(rootClass)) {

         proxySuperClass = rootClass.getSuperclass();

        // 另外还拿到目标对象一堆接口,收集起来后面有用

         Class<?>[] additionalInterfaces = rootClass.getInterfaces();

         for (Class<?> additionalInterface : additionalInterfaces) {

            this.advised.addInterface(additionalInterface);

         }

      }

      // 这里会去检查目标对象的final method,以及当前classLoader可不可以加载到这个目标对象,先去看这个方法

      validateClassIfNecessary(proxySuperClass, classLoader);

      // 这一步是直接new个增强器出来

      Enhancer enhancer = createEnhancer();

      if (classLoader != null) {

         enhancer.setClassLoader(classLoader);

         if (classLoader instanceof SmartClassLoader &&

               ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {

            enhancer.setUseCache(false);

         }

      }

        // 给增强器配置一些参数,目标对象、目标接口、命名策略(BySpringCGLIB)

      enhancer.setSuperclass(proxySuperClass);

      enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));

      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);

      enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

    // 拿到所有的回调对象,主要就是aop的通知拦截器,目标对象方法拦截器(MethodInteceptor)

      Callback[] callbacks = getCallbacks(rootClass);

      Class<?>[] types = new Class<?>[callbacks.length];

      for (int x = 0; x < types.length; x++) {

         types[x] = callbacks[x].getClass();

      }

      // fixedInterceptorMap only populated at this point, after getCallbacks call above

      enhancer.setCallbackFilter(new Prox
<think>我们正在讨论CGLIB代理生成对象的流程。根据引用[1][2][3][5],CGLIB(Code Generation Library)是一个强大的、高性能的代码生成库,它通过动态生成代理类的子类来实现代理。与JDK动态代理不同,CGLIB不需要目标类实现接口,它可以代理普通类。 CGLIB代理生成对象的流程如下: ### 1. **创建Enhancer对象** - 首先,需要创建一个`Enhancer`对象,它是CGLIB的核心类,用于设置代理的配置并生成代理类。 - 示例代码: ```java Enhancer enhancer = new Enhancer(); ``` ### 2. **设置被代理类(父类)** - 使用`setSuperclass()`方法指定要被代理的类(即目标类)。CGLIB生成一个继承自该类的子类作为代理类。 - 示例代码: ```java enhancer.setSuperclass(MyCalculate.class); // MyCalculate是目标类 ``` ### 3. **设置回调(拦截器)** - 通过`setCallback()`方法设置回调对象,该对象需要实现`MethodInterceptor`接口。在代理类的方法被调用时,会触发`intercept`方法,我们可以在该方法中添加自定义逻辑(如日志、事务等)。 - 注意:可以设置多个回调,但这里我们主要讨论单个回调的情况。 - 示例代码: ```java enhancer.setCallback(new MyCglib()); // MyCglib实现了MethodInterceptor ``` ### 4. **创建代理对象** - 调用`create()`方法生成代理对象。这一步会动态生成代理类的字节码,并实例化代理对象。 - 示例代码: ```java MyCalculate proxy = (MyCalculate) enhancer.create(); ``` ### 5. **调用代理对象的方法** - 当调用代理对象的方法时,会触发`MethodInterceptor`的`intercept`方法。在该方法中,我们可以: - 在目标方法执行前插入逻辑(如前置通知)。 - 通过`MethodProxy.invokeSuper()`调用目标类的方法(即父类的方法)。 - 在目标方法执行后插入逻辑(如后置通知)。 - 示例`intercept`方法实现: ```java public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before method: " + method.getName()); Object result = proxy.invokeSuper(obj, args); // 调用目标类的方法 System.out.println("After method: " + method.getName()); return result; } ``` ### 6. **字节码生成与加载(底层原理)** - **生成代理类字节码**:CGLIB使用ASM库在内存中生成代理类的字节码。代理类继承自目标类,并重写了所有非final的方法。 - **加载代理类**:通过自定义的类加载器(通常是`Enhancer`内部的`AbstractClassGenerator.ClassLoaderData`)加载生成的字节码,生成Class对象。 - **实例化代理对象**:通过反射机制创建代理类的实例。 ### 7. **方法调用流程** - 当调用代理对象的方法时,流程如下: 1. 代理对象的方法被调用(例如`proxy.add()`)。 2. 该方法已被代理类重写,其内部会调用`MethodInterceptor.intercept()`方法。 3. 在`intercept`方法中,我们通过`MethodProxy.invokeSuper()`调用目标类(父类)的原始方法。 4. 目标类的方法执行。 5. 返回结果,继续执行`intercept`方法中的后续逻辑。 ### 示例流程(引用[5]的代码) ```java public class MyTest { public static void main(String[] args){ // 设置保存生成的字节码文件(用于调试) System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/path/to/save"); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(MyCalculate.class); // 目标类 enhancer.setCallback(new MyCglib()); // 拦截器 // 创建代理对象 MyCalculate myCalculate = (MyCalculate)enhancer.create(); // 调用方法 myCalculate.add(); } } ``` - 执行`myCalculate.add()`时: 1. 进入`MyCglib.intercept()`方法。 2. 执行前置逻辑(打印"add调用前")。 3. 调用`methodProxy.invokeSuper()`执行`MyCalculate.add()`方法。 4. 在`MyCalculate.add()`内部调用`minus()`方法时,同样会被代理(因为代理对象重写了所有方法),再次进入`intercept`方法。 5. 执行`MyCalculate.minus()`的原始逻辑。 6. 返回后执行后置逻辑(打印"add调用后")。 ### 关键点总结 - **代理类继承目标类**:CGLIB通过生成目标类的子类来实现代理,因此不能代理final类或final方法[^1][^3]。 - **方法拦截**:所有非final方法都会被重写,调用时转向`MethodInterceptor.intercept`。 - **高性能**:CGLIB通过`MethodProxy`直接调用父类方法,避免了反射开销,比JDK代理更快[^5]。 §§相关问题§§ 1. CGLIB代理JDK动态代理的主要区别是什么? 2. 如何避免CGLIB代理final方法的代理? 3. CGLIB生成代理类在JVM中如何加载? : 引用自刨析Spring AOP的Cglib代理实现。 [^2]: 引用自cglib动态代理使用和源码分析心得。 [^3]: 引用自Spring进阶 - Spring AOP实现原理(三)Cglib代理实现。 [^4]: 引用自CGLib动态代理。 [^5]: 引用自cglib代理对象调用方法的执行流程。 </think> ### CGLIB代理生成对象的流程详解 CGLIB(Code Generation Library)是一个强大的字节码生成库,通过动态生成代理类的子类来实现代理。以下是详细的创建流程(基于引用[1][2][3][5]): #### 1. **创建Enhancer对象** ```java Enhancer enhancer = new Enhancer(); ``` - `Enhancer`是CGLIB的核心类,负责生成代理对象 - 初始化配置参数(如生成策略、类加载器等) #### 2. **设置父类(被代理类)** ```java enhancer.setSuperclass(MyCalculate.class); // 指定被代理的类 ``` - 通过继承方式实现代理生成代理类是被代理类的子类) - **限制**:无法代理final类或final方法 #### 3. **设置回调拦截器** ```java enhancer.setCallback(new MyCglib()); // 实现MethodInterceptor接口 ``` - `MethodInterceptor`接口包含核心方法: ```java public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 前置增强 Object result = proxy.invokeSuper(obj, args); // 调用父类方法 // 后置增强 return result; } ``` #### 4. **生成代理类字节码(关键步骤)** ```java MyCalculate proxy = (MyCalculate) enhancer.create(); // 动态生成代理对象[^2] ``` 1. **字节码生成**: - 使用ASM框架动态创建新类的字节码 - 生成代理类的子类(如`MyCalculate$$EnhancerByCGLIB$$xxxx`) 2. **方法重写**: - 为每个非final方法生成重写版本 - 在重写方法中添加拦截逻辑:调用`MethodInterceptor.intercept()` 3. **FastClass机制**: - 生成索引表加速方法调用(避免反射开销) #### 5. **类加载与实例化** - 通过自定义类加载器加载生成的字节码 - 反射实例化代理对象 - 注入回调拦截器引用 #### 6. **方法调用流程示例** ```java proxy.add(); // 调用代理方法 ``` 1. 进入代理类的重写`add()`方法 2. 调用`MethodInterceptor.intercept()` 3. 执行前置增强逻辑(如日志) 4. 通过`MethodProxy.invokeSuper()`调用父类原始方法 5. 执行后置增强逻辑 6. 返回结果 #### 7. **字节码存储(调试用)** ```java System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/path"); ``` - 生成的.class文件包含三部分: 1. 代理类(如`MyCalculate$$EnhancerByCGLIB$$xxxx.class`) 2. 代理类的FastClass(如`MyCalculate$$FastClassByCGLIB$$xxxx.class`) 3. 被代理类的FastClass(如`MyCalculate$$FastClassByCGLIB$$xxxx.class`) ### 核心特点 1. **继承代理**:通过子类化实现,无需接口[^2] 2. **高性能**:FastClass机制比JDK代理快约10倍[^5] 3. **方法拦截**:通过`MethodInterceptor`实现AOP增强 4. **局限性**:无法代理final方法/类;构造方法不会被代理 > 示例:Spring AOP默认对无接口类使用CGLIB代理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值