Skip to content

启用 @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 ApplicationConfiguration
xml
<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 会向容器中注册一个名为 AnnotationAwareAspectJAutoProxyCreatorBean 后置处理器 (BeanPostProcessor)

  • 扫描逻辑:在每个 Bean 实例化后,该处理器会扫描容器中所有的 @Aspect Bean。
  • 匹配逻辑:利用 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 逻辑不生效,请检查以下几点:

  1. 类路径:确保 aspectjweaver 依赖已引入。
  2. Bean 管理:你的切面类(标注 @Aspect 的类)是否也被标注了 @Component?只有被 Spring 管理的类才能发挥切面作用。
  3. 代理语义:你调用的是代理对象的方法吗?(内部调用或 new 出来的对象不走 AOP)。
  4. 方法可见性:Spring AOP 仅支持拦截 public 方法(虽然 CGLIB 能拦截 protected 和包级别方法,但基于可移植性建议仅关注 public)。

Based on Spring Framework.