一、AOP是什么?为什么需要它?
如果你住在一个高档小区,每次进出都需要保安登记、电梯刷卡、门禁验证——这些流程虽然繁琐,但能保障安全。Spring AOP(面向切面编程) 就是代码世界的“保安系统”,它能将日志记录、权限校验、事务管理等横切关注点(CrossCutting Concerns)从业务逻辑中剥离,让核心代码更纯粹。
传统开发的痛点:
• 代码臃肿:日志、事务代码重复出现在每个业务方法中,如“保安站岗在每个房门口”。
• 耦合度高:修改安全规则时,需逐个修改所有相关方法,容易遗漏或出错。
AOP通过动态代理技术,在不修改源码的情况下,为代码插入统一的增强逻辑。就像小区统一部署智能门禁系统,所有住户无需自己装锁,却享受更高效的安全管理。
二、AOP的核心三要素:切面、切点、通知
1. 切面(Aspect)
定义一组公共行为(如日志记录),相当于“保安系统”的规则手册。通过@Aspect注解标识:
@Aspect
publicAspect { / ... / }
2. 切点(Pointcut)
描述哪些方法需要增强,类似“所有住户的入户门”。使用AspectJ表达式定义范围:
@Pointcut("execution( com.example.service..(..))")
public void serviceMethods() {}
3. 通知(Advice)
具体增强逻辑的执行时机,分为五种类型:
• @Before:方法执行前(如登记访问记录)
• @After:方法执行后(无论成功或异常)
• @AfterReturning:方法正常返回后(如记录成功日志)
• @AfterThrowing:方法抛出异常后(如报警通知)
• @Around:包裹整个方法(可控制是否执行原方法,常用于性能监控。
三、动态代理:AOP的“两把钥匙”
Spring AOP的底层实现依赖两种动态代理技术,如同打开增强逻辑的钥匙:
1. JDK动态代理
• 条件:目标类实现了接口
• 原理:通过Proxy.newProxyInstance()生成接口的代理类,拦截方法调用并插入增强逻辑。
• 示例:若UserService实现了IService接口,代理对象会实现IService并重写方法。
2. CGLIB代理
• 条件:目标类未实现接口
• 原理:通过继承目标类生成子类,重写父类方法实现增强(需注意final类无法代理)。
• 优势:无需接口支持,适用于遗留代码改造。
Spring的选择策略:默认优先使用JDK代理,若目标类无接口则切换至CGLIB。
四、AOP的执行流程:从配置到拦截
1. 容器启动阶段
• 扫描切面:识别所有@Aspect注解的类,解析切点和通知。
• 生成代理对象:通过AnnotationAwareAspectJAutoProxyCreator(Bean后置处理器)动态创建代理类替换原始Bean。
2. 方法调用阶段
• 拦截请求:代理对象接管方法调用,根据切点匹配是否需增强。
• 执行通知链:若匹配成功,按顺序执行环绕通知→前置通知→目标方法→后置通知→最终通知。
• 异常处理:若目标方法抛出异常,则触发@AfterThrowing通知。
关键设计:
• 拦截器链(Interceptor Chain):多个通知封装为拦截器,形成责任链模式。
• MethodInvocation对象:封装方法调用上下文,支持递归执行拦截器链。
五、AOP的哲学思考:解耦与效率的平衡
1. 模块化思维的胜利
AOP将横切关注点抽象为独立模块,如同将小区安保外包给专业公司,让开发者专注业务逻辑的“房屋装修”。
2. 性能与灵活性的权衡
动态代理通过反射或字节码增强实现,虽带来轻微性能损耗(约10%20%),但在大多数场景下,其提升的代码可维护性远大于此代价。
3. 设计模式的集大成者
AOP融合了代理模式、责任链模式、工厂模式,体现了“组合优于继承”的设计原则。例如,ProxyFactory封装了代理对象的创建过程。
六、源码级透视:AnnotationAwareAspectJAutoProxyCreator
Spring AOP的核心类AnnotationAwareAspectJAutoProxyCreator(名字长但功能明确)的工作流程:
1. Bean初始化后介入:通过postProcessAfterInitialization方法拦截Bean的创建。
2. 筛选候选Advisor:从容器中获取所有切面,匹配当前Bean是否需要代理。
3. 创建代理对象:根据条件选择JDK或CGLIB生成代理类,如:
// JDK代理核心代码
Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) {
// 执行拦截逻辑
}
});
4. 方法拦截:调用JdkDynamicAopProxy.invoke()或CglibAopProxy.intercept()执行通知链。
结语:AOP与IOC的“黄金组合”
如果说IOC是Spring的“骨架”,AOP则是“神经系统”——前者管理对象的生命周期,后者控制行为增强。二者共同构建了Spring的松耦合架构。想要深入理解AOP,不妨从AbstractAutoProxyCreator和ProxyFactoryBean的源码入手,感受“动态织入”的精妙设计。正如小区有了智能安保才能成为现代化社区,代码有了AOP才能真正迈向高内聚、低耦合的优雅境界。
PS:如果还不了解IOC可以看看上一篇文章哦
(本文参考Spring 5.3.x源码及多篇技术博客整理,推荐阅读org.springframework.aop.framework包下的核心类。)