当前位置: 首页 > news >正文

spring-cglib代理-初探01

一、cglib初探

Spring 中的 CGLIB 是 Spring 框架对 CGLIB(Code Generation Library)字节码生成库的内置集成与适配,主要用于实现动态代理功能,尤其适用于代理没有实现接口的类。以下是对 Spring 中 CGLIB 的核心总结:
一、核心作用
类代理的实现:
当目标对象没有实现接口时,Spring AOP 会默认使用 CGLIB 生成目标类的子类代理(通过继承实现),弥补 JDK 动态代理(仅支持接口代理)的局限。
支持 Spring 核心功能:
@Configuration 类的代理:确保 @Bean 方法间调用复用容器中的 Bean 实例。
AOP 增强:为目标类方法添加日志、事务、权限控制等横切逻辑。
生命周期管理:代理类可集成 Spring 的初始化、销毁等生命周期回调。
二、与原生 CGLIB 的区别
维度	原生 CGLIB(net.sf.cglib)	Spring 内置 CGLIB(org.springframework.cglib)
包路径	net.sf.cglib	org.springframework.cglib
依赖来源	独立引入 cglib:cglib 依赖	内置在 spring-core 模块,无需额外依赖
版本冲突	可能与其他框架的 CGLIB 版本冲突	重新打包后与外部隔离,避免冲突
Spring 兼容性	低(可能与 Spring 机制冲突)	高(深度适配 Spring 代理、类加载等逻辑)
三、核心组件与机制
Enhancer:
生成代理类的核心类,通过 setSuperclass(Class) 指定目标类,setCallback(Callback) 设置拦截器,最终通过 create() 生成代理实例。
MethodInterceptor:
方法拦截器接口,核心方法 intercept(...) 定义增强逻辑,通过 MethodProxy.invokeSuper(proxy, args) 调用目标类的原始方法。
FastClass:
CGLIB 生成的辅助类(如 XXX$$FastClassByCGLIB$$...),通过方法索引替代反射调用,提升代理方法的执行性能。(生成2)
代理类结构:
生成的代理类命名格式为 目标类名$$EnhancerByCGLIB$$随机哈希值,是目标类的子类,重写所有非 final 方法并转发给拦截器处理。
四、典型使用场景
Spring AOP 类代理:
当 @Aspect 切面的切入点匹配非接口类时,自动使用 CGLIB 生成代理,执行 @Before@Around 等通知逻辑。
@Configuration 类代理:
标注 @Configuration 的类会被 CGLIB 代理,确保 @Bean 方法间调用从容器获取实例(而非重复创建),保证单例特性。
自定义类增强:
直接通过 EnhancerMethodInterceptor 实现类的方法增强(如缓存、日志),无需依赖 Spring AOP 上层接口。
五、注意事项
无法代理 final 元素:
final 类不能被继承(无法生成子类代理),final 方法不能被重写(不会执行拦截逻辑)。
避免过度代理:
默认会代理所有非 final 方法,建议通过过滤逻辑(如跳过 toString()hashCode()Object 方法)减少不必要的增强。
性能考量:
代理类生成时会消耗一定资源,但运行时通过 FastClass 优化调用性能,多次调用时效率优于反射。
与 Spring AOP 的关系:
Spring AOP 的底层代理实现可选择 CGLIB 或 JDK 动态代理,CGLIB 适用于类代理,是 Spring 代理机制的重要补充。
总结
Spring 中的 CGLIB 是对原生 CGLIB 的适配与封装,通过动态生成子类实现类代理,支撑了 Spring AOP、@Configuration 等核心功能。其优势在于无需接口即可代理,且与 Spring 生态深度兼容,是处理类增强场景的关键技术。理解其原理有助于更好地排查代理相关问题(如方法未被增强、重复创建实例等)。
一、关于FastClassByCGLIB:确实存在两个
CGLIB 在生成代理类时,会为目标类和代理类分别生成对应的FastClass,因此通常会看到两个FastClassByCGLIB类:
目标类的 FastClass:如SpringService$$FastClassByCGLIB$$xxx,用于快速调用原始目标类的方法(通过方法索引替代反射)。
代理类的 FastClass:如SpringService$$EnhancerByCGLIB$$xxx$$FastClassByCGLIB$$xxx,用于快速调用代理类自身的方法(如 CGLIB 生成的内部方法)。
作用:两者均通过方法索引映射提升调用性能,避免反射开销。目标类的 FastClass 用于调用原始业务方法,代理类的 FastClass 用于代理内部逻辑的快速调用。
二、关于 AOP 与非 final 方法的代理:"代理所有非 final 方法,但仅增强匹配切入点的方法"
CGLIB 的默认行为:
生成的代理类会重写目标类的所有非 final 方法(因为 final 方法无法被继承重写),这意味着从字节码层面,所有非 final 方法都被 "代理" 了(即方法调用会经过代理类)。
Spring AOP 的运行时匹配:
虽然代理类重写了所有非 final 方法,但并非所有方法都会执行增强逻辑。Spring AOP 通过以下机制控制:
启动时,将@Pointcut表达式解析为MethodMatcher(方法匹配器)。
运行时,当代理方法被调用时,MethodMatcher会判断当前方法是否匹配切入点(如servicePointcut)。
若匹配:执行对应的通知(@Before@Around等)增强逻辑。
若不匹配:直接通过MethodProxy.invokeSuper(...)调用目标类的原始方法,等同于 "未增强"。
举例说明:
假设UserServicesave()(业务方法)和toString()Object 方法)两个非 final 方法,且切入点为execution(* save(..)):
代理类会同时重写save()toString()。
调用save()时:匹配切入点,执行增强逻辑(如日志)。
调用toString()时:不匹配切入点,直接执行原始toString()逻辑(无增强)。
总结
FastClassByCGLIB通常有两个,分别对应目标类和代理类,用于提升方法调用性能。
Spring AOP 中,CGLIB 会代理目标类的所有非 final 方法(重写方法并经过代理逻辑),但仅对匹配切入点(如servicePointcut)的方法执行增强,不匹配的方法会直接调用原始逻辑。
这种设计既保证了代理的全面性(避免遗漏需要增强的方法),又通过切入点匹配实现了精准增强,兼顾了灵活性和性能。

二、代理工厂类

package com.fjl.cglib.spring.test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;/**CGLIB 代理工厂类(基于 Class 对象创建代理)入参为被代理类的 Class 和拦截器类的 Class@author jinliang.fan@version 1.0@date 2025/8/7 18:00*/
public class ProxyFactory {/**根据被代理类 Class 和拦截器 Class 创建代理对象@param targetClass 被代理类的 Class 对象@param interceptorClass 拦截器类的 Class 对象(需实现 MethodInterceptor 接口)@param <T> 被代理类的类型@param <R> 拦截器的类型(需实现 MethodInterceptor)@return 代理对象*/@SuppressWarnings ("unchecked")public static <T, R extends MethodInterceptor> T getProxyFactory (Class<T> targetClass, Class<R> interceptorClass) {// 1. 参数校验validateParams (targetClass, interceptorClass);try {// 2. 创建拦截器实例(通过无参构造器)R interceptor = createInterceptorInstance (interceptorClass);// 3. 使用 CGLIB 创建代理Enhancer enhancer = new Enhancer ();enhancer.setSuperclass (targetClass); // 设置父类(被代理类)enhancer.setCallback (interceptor); // 设置拦截器// 4. 生成并返回代理对象(调用被代理类的无参构造器)return (T) enhancer.create ();} catch (Exception e) {throw new RuntimeException ("创建代理对象失败", e);}}/**带参数的代理创建方法(支持被代理类有参构造)@param targetClass 被代理类的 Class@param interceptorClass 拦截器 Class@param targetArgs 被代理类构造器的参数@param <T> 被代理类类型@param <R> 拦截器类型@return 代理对象*/@SuppressWarnings ("unchecked")public static <T, R extends MethodInterceptor> T getProxyFactory (Class<T> targetClass,Class<R> interceptorClass,Object... targetArgs) {validateParams(targetClass, interceptorClass);try {// 创建拦截器实例R interceptor = createInterceptorInstance (interceptorClass);// 创建 EnhancerEnhancer enhancer = new Enhancer ();enhancer.setSuperclass (targetClass);enhancer.setCallback (interceptor);// 获取被代理类的构造器参数类型Class<?>[] argTypes = new Class [targetArgs.length];for (int i = 0; i < targetArgs.length; i++) {argTypes [i] = targetArgs [i].getClass ();}// 调用有参构造器生成代理return (T) enhancer.create (argTypes, targetArgs);} catch (Exception e) {throw new RuntimeException ("创建带参代理对象失败", e);}}/**校验输入参数的合法性*/private static <T, R extends MethodInterceptor> void validateParams (Class<T> targetClass, Class<R> interceptorClass) {if (targetClass == null) {throw new IllegalArgumentException ("被代理类的 Class 不能为 null");}if (interceptorClass == null) {throw new IllegalArgumentException ("拦截器的 Class 不能为 null");}if (!MethodInterceptor.class.isAssignableFrom (interceptorClass)) {throw new IllegalArgumentException ("拦截器类必须实现 MethodInterceptor 接口");}}/**创建拦截器实例(通过无参构造器)*/private static <R extends MethodInterceptor> R createInterceptorInstance(Class<R> interceptorClass)throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {Constructor<R> constructor = interceptorClass.getDeclaredConstructor ();constructor.setAccessible (true); // 支持私有构造器(如果需要)return constructor.newInstance ();}
}
http://www.dtcms.com/a/320056.html

相关文章:

  • 深度学习-卷积神经网络CNN-1×1卷积层
  • Flink-1.19.0源码详解9-ExecutionGraph生成-后篇
  • UE5多人MOBA+GAS 39、制作角色上半身UI
  • 字符串匹配(重点解析KMP算法)
  • 6 大模块!重构物业运营方式
  • 跨境电商增长突围:多维变局下的战略重构与技术赋能
  • 数智先锋 | Bonree ONE 赋能通威股份有限公司提升全栈可观测性能力
  • 深入解析NVIDIA Nsight工具套件:原理、功能与实战指南
  • 房产证识别在房产行业的技术实现及应用原理
  • Python Socket 脚本深度解析与开发指南
  • 扣扣号码展示网站源码_号码售卖展示系统源码 全开源 带后台(源码下载)
  • 5、倒计时翻页效果
  • 工作任务管理
  • 《C语言》指针练习题--1
  • Python入门Day17:函数式编程(map/filter/reduce/lambda)
  • 浏览器渲染与GPU进程通信图解
  • Numpy科学计算与数据分析:Numpy数组操作入门:合并、分割与重塑
  • PWM常用库函数(STC8系列)
  • 【Linux基础知识系列】第八十七篇 - 使用df命令查看磁盘空间
  • 橙河网络:Cint站点如何注册?好做吗?
  • 街道垃圾识别准确率↑32%:陌讯多模态融合算法实战解析
  • 解锁制药新质生产力:合规与效率双赢的数字化转型之道
  • 基于肌电信号的神经网络动作识别系统
  • docker mysql 5.6
  • CSS--:root指定变量,其他元素引用
  • 【题解】洛谷P3172 [CQOI2015] 选数[杜教筛]
  • 【mtcnn】--论文详解重点001之窗口滑动~
  • 板块三章节4——iSCSI 服务器(待更新)
  • python数据结构与算法(基础)
  • 栅栏密码的加密解密原理