启用 @AspectJ 支持 (Enabling @AspectJ Support)
要在 Spring 配置中使用 @AspectJ 切面,你需要启用 Spring 对“基于 @AspectJ 切面配置 Spring AOP”以及“根据这些切面自动为 Bean 创建代理(Auto-proxying)”的支持。
自动代理(Auto-proxying) 指的是:如果 Spring 确定某个 Bean 被一个或多个切面所通知(Advised),它将自动为该 Bean 生成一个代理,以拦截方法调用并确保按需运行通知。
@AspectJ 支持可以通过编程方式(Java 配置)或 XML 配置启用。无论哪种方式,你都需要确保 AspectJ 的 org.aspectj:aspectjweaver 库位于应用程序的类路径(Classpath)中(版本 1.9 或更高)。
java
@Configuration
@EnableAspectJAutoProxy
public class ApplicationConfiguration {
}kotlin
@Configuration
@EnableAspectJAutoProxy
class ApplicationConfigurationxml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 启用 @AspectJ 自动代理 -->
<aop:aspectj-autoproxy />
</beans>补充教学
1. @EnableAspectJAutoProxy 内部发生了什么?
当你添加这个注解时,Spring 会向容器中注册一个名为 AnnotationAwareAspectJAutoProxyCreator 的 Bean 后置处理器 (BeanPostProcessor)。
- 扫描逻辑:在每个 Bean 实例化后,该处理器会扫描容器中所有的
@AspectBean。 - 匹配逻辑:利用 AspectJ 库检查当前 Bean 是否匹配任何切入点表达式。
- 创建代理:如果匹配成功,它会根据配置(JDK 代理或 CGLIB)动态创建一个代理对象,并将其替换掉原始的 Bean 存入容器。
2. 核心配置参数详解
@EnableAspectJAutoProxy 注解(以及 XML 中的 <aop:aspectj-autoproxy />)提供了一些关键参数:
proxyTargetClass(默认为false):false: 优先使用 JDK 动态代理(如果目标类有接口)。true: 强制使用 CGLIB 代理。在 Spring Boot 中,为了避免某些接口转换异常,该值通常默认为true。
exposeProxy(默认为false):- 这是一个“黑科技”参数。如果设置为
true,Spring 允许你通过AopContext.currentProxy()获取当前的代理对象。 - 用途:解决“类内部方法互调导致 AOP 失效”的问题(虽然更好的办法是重构代码,但有时这是唯一的解法)。
- 这是一个“黑科技”参数。如果设置为
3. Spring Boot 中的“自动开启”
在现代 Spring Boot 2.x/3.x 项目中,你通常不需要显式写 @EnableAspectJAutoProxy。
- 只要你引入了
spring-boot-starter-aop,Spring Boot 就会通过其自动配置机制(AopAutoConfiguration)默认开启 AOP 支持。 - 它是通过
spring.aop.auto=true这个配置项来控制的。
4. 常见问题排查(Checklist)
如果你的 AOP 逻辑不生效,请检查以下几点:
- 类路径:确保
aspectjweaver依赖已引入。 - Bean 管理:你的切面类(标注
@Aspect的类)是否也被标注了@Component?只有被 Spring 管理的类才能发挥切面作用。 - 代理语义:你调用的是代理对象的方法吗?(内部调用或
new出来的对象不走 AOP)。 - 方法可见性:Spring AOP 仅支持拦截
public方法(虽然 CGLIB 能拦截protected和包级别方法,但基于可移植性建议仅关注public)。