AOP代理
Spring AOP通过动态代理机制实现切面织入,代理对象在调用目标方法前后执行通知逻辑。
两种代理方式
JDK动态代理
基于接口的代理,要求目标类实现至少一个接口。
Java
// 目标类必须实现接口
public interface UserService {
void save();
}
public class UserServiceImpl implements UserService {
public void save() {
System.out.println("保存用户");
}
}
CGLIB代理
基于继承的代理,通过生成目标类的子类实现代理。
Java
// 目标类无需实现接口
@Service
public class UserService {
public void save() {
System.out.println("保存用户");
}
}
代理选择规则
| 条件 | 代理方式 |
|---|---|
| 目标类实现接口 | JDK动态代理(默认) |
| 目标类无接口 | CGLIB代理 |
| 强制使用CGLIB | 设置 proxyTargetClass=true |
配置方式
强制使用CGLIB
Java
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AopConfig {
}
properties
# application.properties
spring.aop.proxy-target-class=true
代理对象创建过程
Java
// 1. Spring容器启动时检测切面
// 2. 发现目标Bean匹配切入点
// 3. 创建代理对象替代目标Bean
// 4. 注入到其他Bean的是代理对象
@Service
public class OrderService {
@Autowired
private UserService userService; // 注入的是代理对象
}
代理调用流程
Java
客户端调用 → 代理对象 → 前置通知 → 目标方法 → 后置通知 → 返回结果
text
@Around("execution(* com.example.service.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 1. 前置逻辑
System.out.println("方法开始");
// 2. 调用目标方法
Object result = joinPoint.proceed();
// 3. 后置逻辑
System.out.println("方法结束");
return result;
}
两种代理对比
| 特性 | JDK动态代理 | CGLIB代理 |
|---|---|---|
| 实现方式 | 接口实现 | 继承子类 |
| 性能 | 生成快,调用慢 | 生成慢,调用快 |
| 限制 | 必须有接口 | 不能代理final类/方法 |
| Spring默认 | 有接口时使用 | 无接口时使用 |
Spring 5.x后CGLIB性能优化,两种代理性能差异可忽略。
要点总结
- Spring AOP使用JDK动态代理和CGLIB两种代理方式
- 有接口默认用JDK代理,无接口用CGLIB代理
- 可通过
proxyTargetClass=true强制使用CGLIB - 代理对象在容器启动时创建,替代目标Bean注入
- CGLIB不能代理final类和final方法
📝 发现内容有误?点击此处直接编辑