题目
Spring AOP中JDK动态代理与CGLIB代理的区别及使用场景
信息
- 类型:问答
- 难度:⭐⭐
考点
代理机制理解,JDK动态代理与CGLIB区别,Spring AOP配置原理
快速回答
核心要点:
- JDK动态代理基于接口,通过
Proxy类创建代理对象,要求目标类实现接口 - CGLIB代理通过字节码增强生成目标类的子类作为代理,无需接口
- Spring默认优先使用JDK动态代理,无接口时自动切换CGLIB
- 强制使用CGLIB需配置
@EnableAspectJAutoProxy(proxyTargetClass=true)
一、代理机制原理
Spring AOP 通过代理模式实现切面功能:
- JDK动态代理:基于Java反射API,运行时动态生成实现目标接口的代理类
- CGLIB代理:通过ASM字节码操作库,生成目标类的子类并重写方法
二、核心区别对比
| 特性 | JDK动态代理 | CGLIB代理 |
|---|---|---|
| 依赖要求 | 目标类必须实现接口 | 无需接口,可代理普通类 |
| 代理对象类型 | 实现相同接口的新类 | 目标类的子类 |
| 性能表现 | 创建快,执行稍慢 | 创建慢(需字节码生成),执行快 |
| final方法限制 | 无限制 | 无法代理final方法/类 |
三、代码示例
JDK代理使用示例:
public interface UserService {
void saveUser();
}
public class UserServiceImpl implements UserService {
@Override
public void saveUser() {
System.out.println("保存用户");
}
}
// Spring自动创建代理(需接口)
@Autowired
private UserService userService; // 实际为Proxy实例CGLIB代理配置:
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用CGLIB
public class AppConfig {}四、使用场景建议
- 优先JDK动态代理:业务类已实现接口时(符合面向接口编程原则)
- 必须CGLIB:
- 代理未实现接口的类
- 需要代理非public方法
- 目标对象被多次代理(避免JDK代理嵌套问题)
五、常见错误
- 错误1:对未实现接口的类未配置proxyTargetClass,导致代理失败
- 错误2:在代理类中调用内部方法(this.xxx())绕过切面,应通过AopContext获取代理对象
- 错误3:尝试代理final方法(CGLIB会忽略切面)
六、扩展知识
- 性能优化:Spring 4.x后CGLIB创建性能大幅提升,差距缩小
- Objenesis库:CGLIB通过该库跳过构造函数创建代理实例
- Spring Boot默认:2.x版本开始默认使用CGLIB(因多数场景无接口)