赞
踩
CGLIB是一个强大的、高性能的代码生成库。它被广泛应用于AOP(面向切面编程)、ORM(对象关系映射)和其他一些框架中。
CGLIB代理的基本原理:
ASM
字节码操作框架,在运行时动态生成目标类的子类。这个子类会继承自目标类。final
的方法。覆盖的方法会委托给一个用户定义的拦截器(MethodInterceptor
),拦截器中包含了增强的代码。CGLIB代理的特点:
CGLIB通过操纵字节码,创建出目标类的子类,并在子类中覆盖非final的方法,从而实现方法拦截和增强。
CGLIB创建代理类的基本步骤:
CGLIB
代理不需要目标类实现任何接口,因为它是通过继承的方式来实现代理的。Enhancer
是CGLIB
中的一个核心类,用于创建代理类。首先创建一个Enhancer
实例,并设置其父类(即目标类)。Callback
是一个接口,用于定义代理类中覆盖方法的逻辑。通常使用MethodInterceptor
接口,它允许我们在调用原始方法之前和之后插入自定义代码。将实现的Callback
对象设置给Enhancer
。Enhancer
的create()
方法,CGLIB
会使用ASM
字节码操作框架来动态生成一个继承自目标类的子类。这个子类会覆盖所有非final
的方法,并将调用委托给Callback
对象。create()
方法返回的是一个代理类的实例,这个实例可以被当作目标类的实例来使用。当调用代理类的方法时,实际上会调用MethodInterceptor
中的intercept()
方法。intercept()
方法中,可以调用Method
对象的invoke()
方法来执行原始方法。这样,我们就可以在原始方法执行前后插入自定义的逻辑,实现方法的拦截和增强。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 中负责生成代理类的核心类。仅展示部分源码,其它源码会在下方解决其它问题时会出现,没有出现的,读者感兴趣可以自行去解读源码。
代理对象的创建过程: 检查是否可以使用缓存的代理对象 -> 准备 CGLIB Enhancer -> 配置 Enhancer -> 设置回调处理器(Callback) -> 生成代理类字节码 -> 创建代理对象实例 -> 将代理对象缓存起来
Enhancer
对象通过调用 create()
方法来生成代理对象。
createHelper()
方法用来实际创建代理对象。
AbstractClassGenerator
对象通过调用 create()
方法,根据给定的键值(key)
创建对象实例。
createProxyClassAndInstance
负责创建代理类的实例,使用 CGLIB
技术创建代理对象,并将指定的拦截器回调方法应用于代理对象上。
通过
ReflectiveMethodInvocation
类了解到在 Spring 框架中如何构建和执行代理链,以及拦截器如何在拦截器链中协作,以实现对目标方法的拦截和处理。
在拦截器链中如何依次执行拦截器,并通过判断和调用不同的拦截器或目标方法来实现拦截和处理逻辑。
invokeJoinpoint()
用于执行目标方法,如果拦截器链中已经没有下一个拦截器了,或者拦截器中的某个拦截器选择不继续执行拦截器链,那么就会调用这个方法来执行目标方法。
定义了方法拦截器的标准,任何实现该接口的类都可以作为 Spring AOP
中的拦截器,用于在目标方法执行前后添加额外的逻辑。
假设有一个简单的服务类
UserService
,其中包含一些方法,希望能够在调用这些方法之前和之后记录日志。使用CGLIB来实现一个拦截器,记录方法调用的开始和结束时间。
public class UserService {
public void createUser(String username) {
System.out.println("Creating user: " + username);
// 模拟创建用户的逻辑
}
public void updateUser(String username) {
System.out.println("Updating user: " + username);
// 模拟更新用户的逻辑
}
}
/**
* 创建 LoggingInterceptor 类,实现 MethodInterceptor 接口
*/
public class LoggingInterceptor implements MethodInterceptor {
/**
* 参数:obj 是被代理的对象实例
* method 是被调用的方法对象
* args 是方法的参数数组
* proxy 是用于调用父类(被代理类)方法的代理对象
*/
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 获取方法调用开始时的时间戳
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;
}
public static void main(String[] args) {
UserService userService = new UserService();
// 使用CGLIB的 Enhancer 类创建了 UserService 类的代理对象,并将拦截器设置为回调方法
Enhancer enhancer = new Enhancer();
// 设置了要代理的目标类是 UserService
enhancer.setSuperclass(UserService.class);
// 指定了在方法调用时应该执行的拦截逻辑
enhancer.setCallback(new LoggingInterceptor());
// 创建代理对象,将会在方法调用时执行我们定义的拦截逻辑
UserService userServiceProxy = (UserService) enhancer.create();
// 调用代理对象的 createUser 和 updateUser 方法来触发拦截器的拦截逻辑
userServiceProxy.createUser("John Doe");
userServiceProxy.updateUser("Jane Smith");
}
}
//输出结果:
Method createUser start at: 1621802728000
Creating user: John Doe
Method createUser end at: 1621802728000
Method createUser execution time: 0 milliseconds
Method updateUser start at: 1621802728000
Updating user: Jane Smith
Method updateUser end at: 1621802728000
Method updateUser execution time: 0 milliseconds
实现对非接口类的代理和增强功能通常使用 Spring AOP来实现,提供了一种便捷的方式来在方法执行前、执行后、方法抛出异常时等时机插入特定逻辑,而无需修改原始类的代码。
假设有一个订单管理系统,其中包含一个 OrderService 类,该类负责处理订单相关的业务逻辑,比如创建订单、更新订单状态等。希望在处理订单相关业务时,记录日志并统计方法执行时间。
@Aspect
@Component
public class OrderAspect {
/**
* 切面方法,用于实现切面的逻辑 -> 表示正在执行目标方法之前
* 接受一个 JoinPoint 参数,连接点 -> 被增强的目标方法
*/
@Before("execution(* com.example.service.OrderService.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before executing method: " + joinPoint.getSignature());
}
/**
* 切面方法,用于实现切面的逻辑 -> 表示目标方法执行完成后
* 接受一个 JoinPoint 参数,连接点 -> 被增强的目标方法
*/
@After("execution(* com.example.service.OrderService.*(..))")
public void logAfter(JoinPoint joinPoint) {
System.out.println("After executing method: " + joinPoint.getSignature());
}
}
/**
* 标识这个类是一个配置类 -> 告诉 Spring 容器如何配置应用程序上下文
* 启用了 AspectJ 自动代理 -> 告诉 Spring 在运行时生成 AOP 代理以支持 @AspectJ 切面
* 指示 Spring 在包 com.example 及其子包中扫描组件 -> 自动发现并注册带有 @Component、@Service、@Repository 和 @Controller 注解的 bean
*/
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}
/**
* 调用 OrderService 类的 createOrder() 或 updateOrderStatus() 方法时,OrderAspect 切面中定义的增强逻辑会在方法执行前后生效,从而实现了对非接口类的代理和增强功能
*/
@Service
public class OrderService {
public void createOrder() {
// 模拟创建订单的业务逻辑
System.out.println("Creating order...");
}
public void updateOrderStatus() {
// 模拟更新订单状态的业务逻辑
System.out.println("Updating order status...");
}
}
// 输出结果:
Before executing method: public void com.example.service.OrderService.createOrder()
Creating order...
After executing method: public void com.example.service.OrderService.createOrder()
Before executing method: public void com.example.service.OrderService.updateOrderStatus()
Updating order status...
After executing method: public void com.example.service.OrderService.updateOrderStatus()
对乐于苦斗的人来说,苦斗不是憾事,而是乐事
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。