1. Spring AOP核心概念回顾
在深入Spring AOP源码之前,我们需要先理解AOP的几个核心概念。AOP(面向切面编程)是Spring框架的重要特性之一,它通过横向切割关注点来增强代码的模块化程度。
1.1 基础术语解析
Advice(通知):定义了在特定连接点执行的动作。Spring支持五种通知类型:
- Before Advice:在方法执行前触发
- After Returning Advice:方法正常返回后触发
- After Throwing Advice:方法抛出异常后触发
- After (Finally) Advice:方法执行后无论结果如何都会触发
- Around Advice:包围方法执行,可以控制是否执行目标方法
Pointcut(切入点):定义了Advice应该应用在哪些连接点上。Spring使用AspectJ的切入点表达式语言来定义匹配规则,例如:
java复制@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
Aspect(切面):是Advice和Pointcut的组合体,定义了"什么"和"何时"两个维度。在Spring中,使用@Aspect注解标注的类就是一个切面。
Advisor(顾问):Spring AOP特有的概念,可以看作是Pointcut和Advice的简单组合。DefaultPointcutAdvisor是最常用的实现类。
1.2 AOP实现原理图解
通过图示可以更直观理解这些概念的关系:

这个架构图展示了AOP的核心组件如何协同工作:
- 通过Pointcut匹配目标方法
- 根据匹配结果应用相应的Advice
- 由Aspect组织这些关系
- 最终通过织入(Weaving)过程将增强逻辑应用到目标对象
2. Spring AOP类结构深度解析
理解Spring AOP的类结构对于掌握其实现原理至关重要。Spring通过精心设计的类层次结构实现了AOP的各种功能。
2.1 Advice类层次结构
Spring中的Advice接口体系如下:

关键接口说明:
- Interceptor:AOP联盟定义的通用拦截器接口
- Advice:Spring AOP的标记接口,没有定义方法
- BeforeAdvice:前置通知标记接口
- AfterAdvice:后置通知标记接口
- MethodInterceptor:方法拦截器,实际执行增强逻辑
实际开发中,我们更常用的是基于注解的Advice,如@Before、@After等,这些注解最终都会被转换为对应的Advice实现类。
2.2 Pointcut设计解析
Pointcut接口定义了如何确定连接点:

核心实现方式:
- 静态切入点:在编译期确定,性能更高
- 动态切入点:在运行时评估,灵活性更强
Spring主要使用AspectJExpressionPointcut,它支持AspectJ的切入点表达式语法:
java复制public class AspectJExpressionPointcut extends AbstractExpressionPointcut {
private final PointcutExpression pointcutExpression;
@Override
public boolean matches(Method method, Class<?> targetClass) {
// 使用AspectJ的匹配逻辑
ShadowMatch shadowMatch = getShadowMatch(method, targetClass);
return shadowMatch.alwaysMatches();
}
}
2.3 Advisor体系解析
Advisor将Pointcut和Advice组合起来:

主要实现类:
- DefaultPointcutAdvisor:通用的Pointcut-Advisor实现
- AspectJPointcutAdvisor:支持AspectJ注解的Advisor
- InstantiationModelAwarePointcutAdvisorImpl:处理@Aspect注解类的内部实现
3. AOP织入实现机制
Spring AOP的核心在于如何将切面逻辑织入到目标对象中。这一过程主要通过BeanPostProcessor和动态代理实现。
3.1 @EnableAspectJAutoProxy解析
启用AOP功能的关键注解是@EnableAspectJAutoProxy:
java复制@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
这个注解会注册AspectJAutoProxyCreator,它是实现AOP织入的核心类:

3.2 AnnotationAwareAspectJAutoProxyCreator
这个类是Spring AOP的核心处理器,继承关系如下:

关键方法解析:
java复制public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
// 检查是否需要为当前bean创建代理
if (shouldSkip(beanClass, beanName)) {
return null;
}
// 创建代理对象的逻辑
return createProxy(beanClass, beanName);
}
3.3 代理创建流程
Spring支持两种代理方式:
- JDK动态代理:基于接口实现
- CGLIB代理:基于子类实现
代理创建通过AopProxyFactory完成:
java复制public interface AopProxyFactory {
AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;
}
DefaultAopProxyFactory是默认实现,其决策逻辑如下:
java复制public AopProxy createAopProxy(AdvisedSupport config) {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
} else {
return new JdkDynamicAopProxy(config);
}
}
4. @Aspect注解解析过程
Spring通过解析@Aspect注解来识别切面并创建相应的Advisor。
4.1 切面发现机制
切面的发现主要在BeanPostProcessor的shouldSkip方法中触发:
java复制protected boolean shouldSkip(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
4.2 构建Advisor链
buildAspectJAdvisors方法负责构建所有切面对应的Advisor:
java复制public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) continue;
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
} else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
// 处理perthis/pertarget切面
else {
// ...
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
// 从缓存中获取已解析的Advisor
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
} else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
4.3 方法级Advisor创建
对于每个切面方法,Spring会创建对应的Advisor:
java复制public Advisor getAdvisor(Method candidateAdviceMethod,
MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
// 获取切入点表达式
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 创建Advisor
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
5. AOP代理执行流程
理解代理对象的执行流程对于调试和优化AOP应用至关重要。
5.1 JdkDynamicAopProxy执行逻辑
JDK动态代理的invoke方法处理流程:
java复制public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 处理equals、hashCode等特殊方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
} else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
} else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// 获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 执行拦截器链或直接调用目标方法
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
} else {
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
// 处理返回值
return retVal;
}
5.2 拦截器链执行过程
ReflectiveMethodInvocation的proceed方法实现了责任链模式:
java复制public Object proceed() throws Throwable {
// 如果所有拦截器都执行完毕,则调用目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 获取下一个拦截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 动态方法匹配器处理
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
} else {
return proceed();
}
} else {
// 普通拦截器调用
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
6. 性能优化与最佳实践
在实际项目中使用Spring AOP时,有几个关键点需要注意:
6.1 切入点表达式优化
-
限制匹配范围:尽量缩小切入点表达式的匹配范围
java复制// 不推荐 - 匹配范围太广 @Pointcut("execution(* com..*.*(..))") // 推荐 - 精确匹配特定包下的类 @Pointcut("execution(* com.example.service.*.*(..))") -
避免使用within:within表达式的性能通常比execution差
-
组合使用注解:结合自定义注解可以提升匹配效率
java复制@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Loggable {} @Pointcut("@annotation(com.example.Loggable)") public void loggableMethod() {}
6.2 代理模式选择
-
JDK动态代理:
- 优点:无需额外依赖,创建速度快
- 缺点:只能代理接口
- 适用场景:目标对象实现了接口
-
CGLIB代理:
- 优点:可以代理类,功能更强大
- 缺点:需要CGLIB库,创建速度稍慢
- 适用场景:目标对象没有实现接口
可以通过@EnableAspectJAutoProxy(proxyTargetClass = true)强制使用CGLIB代理
6.3 常见问题排查
-
Advice不生效:
- 检查是否添加了@EnableAspectJAutoProxy
- 确认切面类被Spring管理(有@Component等注解)
- 检查切入点表达式是否匹配目标方法
-
循环依赖问题:
- 避免在Aspect中注入被代理的Bean
- 使用@Lazy延迟加载
-
性能问题:
- 减少动态切入点的使用
- 合并相似的切面逻辑
- 使用AspectJ编译时织入(CTW)替代运行时织入
7. 高级特性与扩展
Spring AOP提供了一些高级特性,可以满足更复杂的需求。
7.1 引入(Introduction)
引入允许我们向现有类添加新的接口实现:
java复制@Aspect
@Component
public class IntroductionAspect {
@DeclareParents(value = "com.example.service.*+",
defaultImpl = DefaultLockable.class)
public static Lockable mixin;
}
public interface Lockable {
void lock();
void unlock();
boolean isLocked();
}
public class DefaultLockable implements Lockable {
private boolean locked;
public void lock() { this.locked = true; }
public void unlock() { this.locked = false; }
public boolean isLocked() { return this.locked; }
}
7.2 基于配置的AOP
除了注解方式,Spring也支持XML配置AOP:
xml复制<aop:config>
<aop:aspect id="myAspect" ref="aopBean">
<aop:pointcut id="serviceMethods"
expression="execution(* com.example.service.*.*(..))"/>
<aop:before pointcut-ref="serviceMethods" method="beforeAdvice"/>
<aop:after-returning pointcut-ref="serviceMethods"
method="afterReturning" returning="result"/>
</aop:aspect>
</aop:config>
7.3 LTW(Load-Time Weaving)
Spring支持AspectJ的加载时织入,需要在启动时添加JVM参数:
code复制-javaagent:/path/to/spring-instrument.jar
配置类需要添加@EnableLoadTimeWeaving:
java复制@Configuration
@EnableLoadTimeWeaving
public class AppConfig {
// ...
}
8. 源码分析技巧
阅读Spring AOP源码时,可以重点关注以下几个关键类:
- AnnotationAwareAspectJAutoProxyCreator:AOP处理的核心类
- AbstractAutoProxyCreator:代理创建的模板类
- AspectJExpressionPointcut:切入点表达式解析
- ReflectiveMethodInvocation:拦截器链执行
- JdkDynamicAopProxy/CglibAopProxy:代理实现
调试技巧:
- 在AbstractAutoProxyCreator.postProcessAfterInitialization方法设置断点
- 观察getAdvicesAndAdvisorsForBean方法的调用过程
- 跟踪createProxy方法的执行流程
理解Spring AOP的实现原理不仅有助于我们更好地使用它,也能在遇到问题时快速定位原因。通过深入源码,我们可以掌握框架的设计思想,提升自己的架构能力。