CGLIB(Code Generation Library)是一个强大的字节码生成库,它在运行时动态生成被代理类的子类,通过继承的方式实现代理。由于不需要接口,CGLIB 可以代理普通类,弥补了 JDK 动态代理必须基于接口的局限性。
核心特性
- 无需接口:通过继承目标类生成代理子类。
- 方法拦截:通过
MethodInterceptor接口实现方法增强。 - 性能优化:使用 FastClass 机制避免反射调用,提升性能。
实现原理
- 继承目标类:生成目标类的子类,重写非 final 方法。
- 方法拦截:在子类中调用
MethodInterceptor.intercept()实现对方法的增强。 - 字节码操作:基于 ASM 框架直接操作字节码生成代理类。
代码示例
1. 添加依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
2. 目标类(无需接口)
public class UserService {
public void addUser(String name) {
System.out.println("添加用户: " + name);
}
public final void finalMethod() {
System.out.println("Final 方法,无法被代理");
}
}
3. 方法拦截器
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class UserServiceInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("[CGLIB] 前置处理: " + method.getName());
Object result = proxy.invokeSuper(obj, args); // 调用父类(目标类)方法
System.out.println("[CGLIB] 后置处理");
return result;
}
}
4. 生成代理对象
import net.sf.cglib.proxy.Enhancer;
public class CglibDemo {
public static void main(String[] args) {
// 1. 创建 Enhancer 实例
Enhancer enhancer = new Enhancer();
// 2. 设置父类(目标类)
enhancer.setSuperclass(UserService.class);
// 3. 设置回调(方法拦截器)
enhancer.setCallback(new UserServiceInterceptor());
// 4. 创建代理对象
UserService proxy = (UserService) enhancer.create();
// 5. 调用代理方法
proxy.addUser("Alice");
// 输出:
// [CGLIB] 前置处理: addUser
// 添加用户: Alice
// [CGLIB] 后置处理
proxy.finalMethod(); // 直接调用父类 final 方法,无增强
// 输出: Final 方法,无法被代理
}
}
CGLIB 关键组件
- Enhancer:用于生成代理类的核心类,设置父类和方法拦截器。
- MethodInterceptor:方法拦截器接口,实现横切逻辑。
- CallbackFilter:根据方法选择不同的回调策略。
局限性
- 无法代理 final 类/方法:因为 CGLIB 通过继承实现。
- 构造方法调用自身方法时无法增强:由于目标类内部调用不会经过代理类。
public class UserService { public void methodA() { methodB(); // 直接调用,不会被拦截 } public void methodB() { ... } }
CGLIB vs JDK 动态代理
| 特性 | CGLIB | JDK 动态代理 |
|---|---|---|
| 代理方式 | 继承 | 接口实现 |
| 目标类要求 | 非 final 类/方法 | 必须实现接口 |
| 性能 | 通常更快(FastClass 优化) | 反射调用稍慢 |
| 依赖 | ASM 字节库 | Java 原生 API |
Spring 中的选择
- 若目标类实现了接口,默认使用 JDK 动态代理。
- 若目标类未实现接口,使用 CGLIB。
- 可通过
@EnableAspectJAutoProxy(proxyTargetClass = true)强制使用 CGLIB。
总结
CGLIB 通过动态生成子类实现代理,适用于无接口的普通类,提供了灵活的方法拦截机制。尽管有 final 方法的限制,但其高性能和广泛的应用场景(如 Spring AOP、Hibernate)使其成为 Java 生态中不可或缺的工具。


3114

被折叠的 条评论
为什么被折叠?



