
文章目录
一、CGLIB 代理简介
1.1 CGLIB 代理的基本原理和特点
CGLIB是一个强大的、高性能的代码生成库。它被广泛应用于AOP(面向切面编程)、ORM(对象关系映射)和其他一些框架中。
CGLIB代理的基本原理:
- 创建代理类:CGLIB通过
ASM字节码操作框架,在运行时动态生成目标类的子类。这个子类会继承自目标类。 - 方法拦截:在生成的子类中,会覆盖所有非
final的方法。覆盖的方法会委托给一个用户定义的拦截器(MethodInterceptor),拦截器中包含了增强的代码。 - 调用流程:当调用代理类的方法时,实际上是在调用被覆盖的方法。这些方法内部会调用拦截器,拦截器再去调用原始类的相应方法。
CGLIB代理的特点:
- 无需接口:CGLIB代理不需要目标类实现任何接口,因为它是通过继承的方式来实现代理的。
- 性能:CGLIB生成的代理类是目标类的子类,相比于JDK动态代理(接口代理),CGLIB代理通常有更好的性能,因为它直接调用父类的方法,减少了反射调用的开销。
- 灵活性:由于CGLIB代理是通过继承实现的,它无法代理final类和方法。但是,它提供了比JDK代理更高的灵活性,因为它可以代理任何类,而不受接口限制。
- 复杂性:CGLIB代理的实现比JDK动态代理复杂,因为它涉及到字节码生成和类加载机制。
- 兼容性:CGLIB代理通常与Spring框架结合使用,Spring AOP默认使用JDK动态代理,但如果目标对象没有实现接口,Spring AOP会自动切换到CGLIB代理。
1.2 分析 CGLIB 如何通过字节码技术创建代理类
CGLIB通过操纵字节码,创建出目标类的子类,并在子类中覆盖非final的方法,从而实现方法拦截和增强。
CGLIB创建代理类的基本步骤:
- 确定目标类:首先要确定需要被代理的目标类。
CGLIB代理不需要目标类实现任何接口,因为它是通过继承的方式来实现代理的。 - 创建Enhancer对象:
Enhancer是CGLIB中的一个核心类,用于创建代理类。首先创建一个Enhancer实例,并设置其父类(即目标类)。 - 设置Callback:
Callback是一个接口,用于定义代理类中覆盖方法的逻辑。通常使用MethodInterceptor接口,它允许我们在调用原始方法之前和之后插入自定义代码。将实现的Callback对象设置给Enhancer。 - 创建代理类:调用
Enhancer的create()方法,CGLIB会使用ASM字节码操作框架来动态生成一个继承自目标类的子类。这个子类会覆盖所有非final的方法,并将调用委托给Callback对象。 - 使用代理类:
create()方法返回的是一个代理类的实例,这个实例可以被当作目标类的实例来使用。当调用代理类的方法时,实际上会调用MethodInterceptor中的intercept()方法。 - 方法调用流程:在
intercept()方法中,可以调用Method对象的invoke()方法来执行原始方法。这样,我们就可以在原始方法执行前后插入自定义的逻辑,实现方法的拦截和增强。
二、深入分析 CglibAopProxy 类的结构
2.1 CglibAopProxy 类结构
- 成员变量: -
AdvisedSupport advised:存储了AOP配置信息的数据结构,如目标对象、切面等。-Callback callback:CGLIB 回调对象,负责实现代理逻辑。 - 构造方法: -
CglibAopProxy(AdvisedSupport config):构造方法接收一个AdvisedSupport参数,用于设置AOP配置信息。 - 核心方法: -
getProxy(ClassLoader classLoader):生成代理对象的核心方法,接收一个 ClassLoader 参数用于加载代理类。-createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks):使用 CGLIB 的 Enhancer 创建代理类,并返回代理对象的实例。-proxy(ClassLoader classLoader, Callback[] callbacks):创建代理类并生成代理对象的实现逻辑, 使用 Enhancer 创建代理类,并指定 Callback 对象,完成代理类的生成和实例化。-createEnhancer():创建 Enhancer 对象,用于生成代理类, Enhancer 是 CGLIB 中负责生成代理类的核心类。
2.2 CglibAopProxy 类源码
仅展示部分源码,其它源码会在下方解决其它问题时会出现,没有出现的,读者感兴趣可以自行去解读源码。

三、CGLIB 代理对象的创建过程
代理对象的创建过程: 检查是否可以使用缓存的代理对象 -> 准备 CGLIB Enhancer -> 配置 Enhancer -> 设置回调处理器(Callback) -> 生成代理类字节码 -> 创建代理对象实例 -> 将代理对象缓存起来
3.1 配置 Enhancer 生成代理对象
Enhancer
对象通过调用
create()
方法来生成代理对象。

createHelper()
方法用来实际创建代理对象。

AbstractClassGenerator
对象通过调用
create()
方法,根据给定的键值
(key)
创建对象实例。

3.2 探讨如何通过字节码生成技术嵌入拦截器逻辑到代理类中
**
createProxyClassAndInstance
** 负责创建代理类的实例,使用
CGLIB
技术创建代理对象,并将指定的拦截器回调方法应用于代理对象上。

四、CGLIB 代理链的处理
通过
ReflectiveMethodInvocation类了解到在 Spring 框架中如何构建和执行代理链,以及拦截器如何在拦截器链中协作,以实现对目标方法的拦截和处理。
4.1 拦截器的调用顺序
在拦截器链中如何依次执行拦截器,并通过判断和调用不同的拦截器或目标方法来实现拦截和处理逻辑。

invokeJoinpoint()
用于执行目标方法,如果拦截器链中已经没有下一个拦截器了,或者拦截器中的某个拦截器选择不继续执行拦截器链,那么就会调用这个方法来执行目标方法。

4.2 实现拦截器具体逻辑
定义了方法拦截器的标准,任何实现该接口的类都可以作为
Spring AOP
中的拦截器,用于在目标方法执行前后添加额外的逻辑。

五、实践与应用
5.1 编写自定义的 CGLIB 拦截器
假设有一个简单的服务类
UserService,其中包含一些方法,希望能够在调用这些方法之前和之后记录日志。使用CGLIB来实现一个拦截器,记录方法调用的开始和结束时间。
- 服务类 UserService,模拟创建和更新用户信息。
publicclassUserService{publicvoidcreateUser(String username){System.out.println("Creating user: "+ username);// 模拟创建用户的逻辑}publicvoidupdateUser(String username){System.out.println("Updating user: "+ username);// 模拟更新用户的逻辑}}
- 自定义的CGLIB拦截器,用于记录方法调用的开始和结束时间。
/**
* 创建 LoggingInterceptor 类,实现 MethodInterceptor 接口
*/publicclassLoggingInterceptorimplementsMethodInterceptor{/**
* 参数:obj 是被代理的对象实例
* method 是被调用的方法对象
* args 是方法的参数数组
* proxy 是用于调用父类(被代理类)方法的代理对象
*/publicObjectintercept(Object obj,Method method,Object[] args,MethodProxy proxy)throwsThrowable{// 获取方法调用开始时的时间戳long startTime =System.currentTimeMillis();System.out.println("Method "+ method.getName()+" start at: "+ startTime);// 调用被代理类的原始方法,而不是代理对象的方法,以避免循环调用Object result = proxy.invokeSuper(obj, args);// 获取方法调用结束时的时间戳long endTime =System.currentTimeMillis();System.out.println("Method "+ method.getName()+" end at: "+ endTime);// 方法执行所花费的时间System.out.println("Method "+ method.getName()+" execution time: "+(endTime - startTime)+" milliseconds");// 调用原始方法后的返回值return result;}publicstaticvoidmain(String[] args){UserService userService =newUserService();// 使用CGLIB的 Enhancer 类创建了 UserService 类的代理对象,并将拦截器设置为回调方法Enhancer enhancer =newEnhancer();// 设置了要代理的目标类是 UserService
enhancer.setSuperclass(UserService.class);// 指定了在方法调用时应该执行的拦截逻辑
enhancer.setCallback(newLoggingInterceptor());// 创建代理对象,将会在方法调用时执行我们定义的拦截逻辑UserService userServiceProxy =(UserService) enhancer.create();// 调用代理对象的 createUser 和 updateUser 方法来触发拦截器的拦截逻辑
userServiceProxy.createUser("John Doe");
userServiceProxy.updateUser("Jane Smith");}}//输出结果:Method createUser start at:1621802728000Creating user:JohnDoeMethod createUser end at:1621802728000Method createUser execution time:0 milliseconds
Method updateUser start at:1621802728000Updating user:JaneSmithMethod updateUser end at:1621802728000Method updateUser execution time:0 milliseconds
5.2 实现对非接口类的代理和增强功能
实现对非接口类的代理和增强功能通常使用 Spring AOP来实现,提供了一种便捷的方式来在方法执行前、执行后、方法抛出异常时等时机插入特定逻辑,而无需修改原始类的代码。
假设有一个订单管理系统,其中包含一个 OrderService 类,该类负责处理订单相关的业务逻辑,比如创建订单、更新订单状态等。希望在处理订单相关业务时,记录日志并统计方法执行时间。
- 切面类 OrderAspect。
@Aspect@ComponentpublicclassOrderAspect{/**
* 切面方法,用于实现切面的逻辑 -> 表示正在执行目标方法之前
* 接受一个 JoinPoint 参数,连接点 -> 被增强的目标方法
*/@Before("execution(* com.example.service.OrderService.*(..))")publicvoidlogBefore(JoinPoint joinPoint){System.out.println("Before executing method: "+ joinPoint.getSignature());}/**
* 切面方法,用于实现切面的逻辑 -> 表示目标方法执行完成后
* 接受一个 JoinPoint 参数,连接点 -> 被增强的目标方法
*/@After("execution(* com.example.service.OrderService.*(..))")publicvoidlogAfter(JoinPoint joinPoint){System.out.println("After executing method: "+ joinPoint.getSignature());}}
- 配置类中启用 Spring AOP 功能。
/**
* 标识这个类是一个配置类 -> 告诉 Spring 容器如何配置应用程序上下文
* 启用了 AspectJ 自动代理 -> 告诉 Spring 在运行时生成 AOP 代理以支持 @AspectJ 切面
* 指示 Spring 在包 com.example 及其子包中扫描组件 -> 自动发现并注册带有 @Component、@Service、@Repository 和 @Controller 注解的 bean
*/@Configuration@EnableAspectJAutoProxy@ComponentScan(basePackages ="com.example")publicclassAppConfig{}
- OrderService 类。
/**
* 调用 OrderService 类的 createOrder() 或 updateOrderStatus() 方法时,OrderAspect 切面中定义的增强逻辑会在方法执行前后生效,从而实现了对非接口类的代理和增强功能
*/@ServicepublicclassOrderService{publicvoidcreateOrder(){// 模拟创建订单的业务逻辑System.out.println("Creating order...");}publicvoidupdateOrderStatus(){// 模拟更新订单状态的业务逻辑System.out.println("Updating order status...");}}// 输出结果:Before executing method:publicvoidcom.example.service.OrderService.createOrder()Creating order...After executing method:publicvoidcom.example.service.OrderService.createOrder()Before executing method:publicvoidcom.example.service.OrderService.updateOrderStatus()Updating order status...After executing method:publicvoidcom.example.service.OrderService.updateOrderStatus()
对乐于苦斗的人来说,苦斗不是憾事,而是乐事
版权归原作者 忆~遂愿 所有, 如有侵权,请联系我们删除。