Spring Boot 自动配置之 Spring‘s AOP
几句话理解 Spring's AOP
- 基于 代理(JDK Proxy / CGLIB)的运行时增强 AOP 实现;
- 默认只拦截 Spring 容器管理的 Bean 的 public 方法;
- 不需要 AspectJ 的编译器或 weaver,Spring 只是借用了 AspectJ 的 注解风格(@Aspect, @Pointcut, @Before, @After 等),但默认并没有用 AspectJ 的编译器或织入器。
拦截原理和时机
容器启动阶段
Spring 在 Bean 初始化阶段(BeanPostProcessor 阶段),通过
AnnotationAwareAspectJAutoProxyCreator
扫描切面类。对匹配切点的 Bean,Spring 会用代理对象替换原始 Bean。
运行时调用阶段
当客户端(例如 Controller 或其他 Bean)调用目标 Bean 的方法时,实际上调用的是代理对象的方法。
代理对象会在 方法执行前、执行后、抛出异常时 或 环绕执行 时,织入切面逻辑。
限制
Spring AOP 只能拦截 Spring 容器管理的 Bean。
默认只支持 方法级别的 Join Point(不像 AspectJ 可以拦截构造函数、字段访问等)。
自调用(同一个类内部方法互调)不会触发代理,因此不会被 AOP 拦截。
自动配置类 AopAutoConfiguration
包:org.springframework.boot.autoconfigure.aop
类:AopAutoConfiguration
package org.springframework.boot.autoconfigure.aop;import org.aspectj.weaver.Advice;import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@AutoConfiguration
@ConditionalOnBooleanProperty(name = "spring.aop.auto", matchIfMissing = true)
public class AopAutoConfiguration {@Configuration(proxyBeanMethods = false)@ConditionalOnClass(Advice.class)static class AspectJAutoProxyingConfiguration {@Configuration(proxyBeanMethods = false)@EnableAspectJAutoProxy(proxyTargetClass = false)@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", havingValue = false)static class JdkDynamicAutoProxyConfiguration {}@Configuration(proxyBeanMethods = false)@EnableAspectJAutoProxy(proxyTargetClass = true)@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", matchIfMissing = true)static class CglibAutoProxyConfiguration {}}@Configuration(proxyBeanMethods = false)@ConditionalOnMissingClass("org.aspectj.weaver.Advice")@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", matchIfMissing = true)static class ClassProxyingConfiguration {@Beanstatic BeanFactoryPostProcessor forceAutoProxyCreatorToUseClassProxying() {return (beanFactory) -> {if (beanFactory instanceof BeanDefinitionRegistry registry) {AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}};}}}
以上是 Spring AOP 自动配置类的完整代码,下面拆开来分析。
@ConditionalOnBooleanProperty(name = "spring.aop.auto", matchIfMissing = true)
自动配置类的生效的先决条件 :"spring.aop.auto" 这个属性值必须为 "true" (默认值,属性缺失时默认为 true),也就是说 Spring AOP 的功能是默认自动开启的。
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration {@Configuration(proxyBeanMethods = false)@EnableAspectJAutoProxy(proxyTargetClass = false)@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", havingValue = false)static class JdkDynamicAutoProxyConfiguration {}@Configuration(proxyBeanMethods = false)@EnableAspectJAutoProxy(proxyTargetClass = true)@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", matchIfMissing = true)static class CglibAutoProxyConfiguration {}}
classpath 上有 AspectJ 的 API
@ConditionalOnClass(Advice.class)
@ConditionalOnClass(Advice.class)
的作用就是:确保 classpath 上有 AspectJ 的 API(至少有 weaver 包),Spring 才能正确解析 @Aspect
注解和切点表达式。一旦缺少这些类,Spring Boot 就不会启用 AspectJAutoProxyingConfiguration
,避免报错。
@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", havingValue = false)
如果属性 “spring.aop.proxy-target-class” 的值为 “false”,则使用 JDK 代理;
@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", matchIfMissing = true)
如果属性 “spring.aop.proxy-target-class” 的值为 “tue” 或 缺失没有配置(缺失时默认为 true),则使用 CGLIB 代理。
classpath 上无 AspectJ 的 API
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
@Configuration(proxyBeanMethods = false)@ConditionalOnMissingClass("org.aspectj.weaver.Advice")@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", matchIfMissing = true)static class ClassProxyingConfiguration {@Beanstatic BeanFactoryPostProcessor forceAutoProxyCreatorToUseClassProxying() {return (beanFactory) -> {if (beanFactory instanceof BeanDefinitionRegistry registry) {AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}};}}
如果 classpath 上无 AspectJ 的 API,并且 "spring.aop.proxy-target-class" 属性值没有明确设置为 “false”,则 Spring AOP 强制使用 CGLIB 代理。
总结:
如果 org.aspectj.weaver.Advice
存在 且 spring.aop.proxy-target-class=false
,Spring Boot 就会自动使用 JDK 动态代理,否则就会使用 CGLIB 代理;且无须手动开启 @EnableAspectJAutoProxy 注解。
如果 org.aspectj.weaver.Advice
不存在且 spring.aop.proxy-target-class=false
时 Spring Boot 的自动 AOP 配置不会生效,换句话说:Spring Boot 不会自动开启基于注解的 AOP;
如果 org.aspectj.weaver.Advice
不存在且 spring.aop.proxy-target-class=true
(默认值)时 Spring Boot 强制使用 CGLIB 代理;这是 Spring Boot AOP 自动配置的“兜底方案”,确保在没有 AspectJ 时,依然能用 CGLIB 代理来启用 AOP;即使没有引入 AspectJ weaver(即没有 org.aspectj.weaver.Advice
),Spring Boot 在兜底方案下依然能让你使用 @Aspect
注解来定义切面。