Spring AOP(Aspect-Oriented Programming)是 Spring 框架的核心功能之一,它通过 动态代理 和 字节码增强 技术,在不修改目标类代码的前提下,实现日志记录、权限控制、事务管理等功能。其底层实现涉及多个核心类和复杂的代理生成逻辑。
🧠 一、Spring AOP 的核心概念
✅ 1. AOP 的基本术语
术语 | 含义 |
---|---|
Aspect(切面) | 横切关注点的模块化,如日志、事务等 |
JoinPoint(连接点) | 程序执行过程中的某个点,如方法调用、异常抛出等 |
Pointcut(切入点) | 定义哪些连接点需要被拦截 |
Advice(通知) | 切面在特定连接点上执行的操作 |
Weaving(织入) | 将切面应用到目标对象并生成代理对象的过程 |
🔄 二、Spring AOP 的实现原理概述
Spring AOP 的核心是 动态代理 和 AOP 代理工厂。其基本流程如下:
1. 解析切面(Aspect) → 2. 创建代理工厂(ProxyFactory) → 3. 生成代理对象(JDK / CGLIB) → 4. 方法调用时拦截并执行切面逻辑
📦 三、关键类与组件
类名 | 作用 |
---|---|
@EnableAspectJAutoProxy | 启用 AOP 自动代理 |
AnnotationAwareAspectJAutoProxyCreator | AOP 自动代理创建器 |
ProxyFactory | 创建代理对象的核心类 |
JdkDynamicAopProxy | 使用 JDK 动态代理 |
CglibAopProxy | 使用 CGLIB 代理(子类继承) |
Advisor / Advice / Pointcut | 描述切面逻辑和匹配规则 |
🧱 四、Spring AOP 的实现流程详解
✅ 1:启用 AOP 支持(@EnableAspectJAutoProxy
)
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
}
@EnableAspectJAutoProxy
注解会导入AspectJAutoProxyRegistrar
。AspectJAutoProxyRegistrar
会注册AnnotationAwareAspectJAutoProxyCreator
Bean。
public class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
}
}
✅ 2:自动代理创建器(AnnotationAwareAspectJAutoProxyCreator
)
该类继承自 AbstractAutoProxyCreator
,负责在 Bean 创建过程中生成代理对象。
核心方法:postProcessAfterInitialization()
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 获取所有匹配的 Advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
// 创建代理对象
return createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
}
}
return bean;
}
✅ 3:创建代理对象(ProxyFactory
)
ProxyFactory
是创建代理的核心类,根据目标类是否实现接口选择代理方式:
protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this.config);
proxyFactory.setTargetSource(targetSource);
// 添加拦截器(切面逻辑)
proxyFactory.addAdvisors(specificInterceptors);
// 决定使用 JDK 动态代理还是 CGLIB
proxyFactory.setProxyTargetClass(proxyTargetClass);
return proxyFactory.getProxy(getProxyClassLoader());
}
✅ 4:生成代理对象(JdkDynamicAopProxy
或 CglibAopProxy
)
4.1 JDK 动态代理(JdkDynamicAopProxy
)
适用于目标类实现了接口的情况:
public Object getProxy(@Nullable ClassLoader classLoader) {
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
4.2 CGLIB 代理(CglibAopProxy
)
适用于目标类没有实现接口的情况:
public Object getProxy(@Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setCallback(new DynamicAdvisedInterceptor(this.advised));
return enhancer.create();
}
✅ 5:拦截方法调用(MethodInterceptor
)
当代理对象的方法被调用时,会进入 DynamicAdvisedInterceptor
(CGLIB)或 JdkDynamicAopProxy
(JDK)的 invoke()
方法。
示例:DynamicAdvisedInterceptor.invoke()
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
MethodInvocation invocation = new CglibMethodInvocation(proxy, target, method, args, targetClass, methodProxy, this.advised);
return invocation.proceed(); // 执行拦截器链
}
✅ 6:执行拦截器链(MethodInterceptor
)
拦截器链由多个 MethodInterceptor
组成,按顺序执行:
public Object proceed() throws Throwable {
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint(); // 执行目标方法
}
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); // 递归执行
}
⚙️ 五、切面逻辑的执行顺序(Advice 顺序)
Spring AOP 支持多种类型的 Advice,它们的执行顺序如下:
类型 | 注解 | 执行顺序 |
---|---|---|
Before Advice | @Before | 在目标方法执行前执行 |
After Returning Advice | @AfterReturning | 在目标方法成功返回后执行 |
After Throwing Advice | @AfterThrowing | 在目标方法抛出异常后执行 |
After (Finally) Advice | @After | 在目标方法执行后(无论是否异常)执行 |
Around Advice | @Around | 包裹目标方法,可控制是否执行目标方法 |
❗ 六、AOP 常见问题与解决方案
Q1: AOP 为什么不能拦截 private 方法?
因为 Spring AOP 基于动态代理,JDK 动态代理只能拦截 public 方法。即使是 CGLIB 代理,也默认不处理非 public 方法。
Q2: AOP 为什么不能拦截内部调用(self-invocation)?
因为代理对象只拦截外部调用。内部调用不会经过代理,导致 AOP 失效。解决方法:
@Autowired
private MyService self;
public void outerMethod() {
self.innerMethod(); // 通过代理调用
}
Q3: AOP 为什么不能拦截构造器?
Spring AOP 只能拦截方法调用,不能拦截构造器。如需拦截构造器,需使用 AspectJ 的编译期织入。
✅ 七、总结
特性 | Spring AOP 实现 |
---|---|
实现方式 | 动态代理(JDK / CGLIB) |
代理生成时机 | Bean 初始化后(postProcessAfterInitialization ) |
通知类型 | Before、After、Around、AfterReturning、AfterThrowing |
执行顺序 | 按拦截器链顺序执行 |
限制 | 仅支持方法拦截,不支持构造器、字段 |
代理失效场景 | 方法非 public、self-invocation、未正确配置 AOP |
🧩 八、完整流程图(简化版)
@EnableAspectJAutoProxy
└── 导入 AspectJAutoProxyRegistrar
└── 注册 AnnotationAwareAspectJAutoProxyCreator
└── Bean 初始化时调用 postProcessAfterInitialization()
└── 获取匹配的 Advisor
└── 创建代理对象(ProxyFactory)
├── JDK 动态代理(接口)
└── CGLIB 代理(子类)
└── 方法调用时进入拦截器链
└── 执行 Around -> Before -> 目标方法 -> After -> AfterReturning / AfterThrowing