
在 Spring 中,AOP(Aspect-Oriented Programming,面向切面编程)通过以下几个步骤收集切面类并进行封装:
1. 定义切面类:
@Aspect 注解来标记,表示这是一个切面。advice),例如 @Before、@After、@Around 等,用于指定在目标方法执行的不同阶段要执行的逻辑。2. 配置切面扫描:
Spring 容器在启动时,会根据配置或注解扫描包路径,寻找带有 @Aspect 注解的类。@EnableAspectJAutoProxy 注解启用 AOP 自动代理机制。3. 解析切面类:
Spring 使用 AspectJAnnotationAutoProxyCreator 或类似的类来扫描和解析 @Aspect 注解的类。Spring 通过反射机制查找切面类中定义的通知方法,并解析这些方法上面的注解,例如 @Before、@After 等。4. 创建切面和通知对象:
Spring 会为每个切面创建 AspectMetadata 对象,并将这些元数据保存在 AdvisedSupport 类中。AdvisedSupport 持有目标对象(被代理的类)和通知(advice)列表。5. 织入切面:
Spring 容器创建 bean 的过程中,如果发现某个 bean 需要 AOP 功能,Spring 会为其创建代理对象。Spring 使用 ProxyFactory 或类似的工厂类,根据目标对象和通知列表创建代理对象。6. 执行代理逻辑:
@Around 通知中,可以在目标方法执行前后执行额外的逻辑,或者在 @Before 通知中执行方法前的逻辑。具体的执行流程如下图所示:
定义切面类:
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before method: " + joinPoint.getSignature().getName());
}
@After("execution(* com.example.service.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
System.out.println("After method: " + joinPoint.getSignature().getName());
}
}配置切面扫描:
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
// other bean definitions
} 通过以上步骤,Spring AOP 机制能够自动收集、解析和织入切面类,实现面向切面编程的功能。这种机制在保持业务逻辑和横切关注点分离的同时,也提升了代码的可读性和可维护性。
在 Spring AOP 中,Advisor 是包含 Advice 和 Pointcut 的一个概念。Advice 是要执行的具体动作(如方法前、后或环绕方法),而 Pointcut 是定义哪些连接点应该应用这些 Advice 的规则。
本节源码基于 spring-aop-5.3.16。
在 Spring AOP 中,Advisor 的构建是通过 AspectJAdvisorFactory 来实现的。ReflectiveAspectJAdvisorFactory 是 AspectJAdvisorFactory 的一个具体实现。
来看看ReflectiveAspectJAdvisorFactory 的 getAdvisors 方法:

源码提出来分析:
/**
* 从给定的 MetadataAwareAspectInstanceFactory 获取所有的 Advisor。
* 这个方法会处理切面类的方法和字段,创建相应的 Advisor 列表。
*
* @param aspectInstanceFactory MetadataAwareAspectInstanceFactory 实例,用于获取切面元数据和实例
* @return 包含所有 Advisor 的列表
*/
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 获取切面类的元数据
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 获取切面类的名称
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
// 验证切面类是否合法
validate(aspectClass);
// 我们需要用一个装饰器包装 MetadataAwareAspectInstanceFactory,以便它只实例化一次
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
// 创建一个保存 Advisor 的列表
List<Advisor> advisors = new ArrayList<>();
// 遍历切面类的方法,获取所有符合条件的 Advisor 方法
for (Method method : getAdvisorMethods(aspectClass)) {
// 在 Spring Framework 5.2.7 之前,advisors.size() 被作为 declarationOrderInAspect
// 提供给 getAdvisor(...) 以表示在已声明方法列表中的“当前位置”。
// 然而,自 Java 7 以来,“当前位置”已不再有效,因为 JDK 不再按源代码中声明的顺序返回声明的方法。
// 因此,我们现在将 declarationOrderInAspect 硬编码为 0,以便通过反射发现的所有通知方法,
// 以支持 JVM 启动期间的可靠通知排序。
// 具体来说,值 0 与 AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor) 中使用的默认值对齐。
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
// 将 Advisor 添加到列表中
advisors.add(advisor);
}
}
// 如果它是每个目标实例化的切面,则发出虚拟实例化的切面
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// 创建并添加一个合成的实例化 Advisor 到列表的开头
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// 查找引入字段
for (Field field : aspectClass.getDeclaredFields()) {
// 获取 DeclareParents 的 Advisor
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
// 将 Advisor 添加到列表中
advisors.add(advisor);
}
}
// 返回所有的 Advisor
return advisors;
}
/**
* 从给定的方法和切面实例工厂获取一个 Advisor。
* 这个方法会处理切面类的方法并创建相应的 Advisor。
*
* @param candidateAdviceMethod 候选的通知方法
* @param aspectInstanceFactory MetadataAwareAspectInstanceFactory 实例,用于获取切面元数据和实例
* @param declarationOrderInAspect 在切面中的声明顺序
* @param aspectName 切面名称
* @return 对应的 Advisor,如果方法没有对应的 Pointcut 则返回 null
*/
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
// 验证切面类是否合法
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 获取 Pointcut
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
// 如果没有对应的 Pointcut,则返回 null
return null;
}
// 创建并返回 InstantiationModelAwarePointcutAdvisorImpl
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
/**
* 获取给定方法的 Pointcut。
*
* @param candidateAdviceMethod 候选的通知方法
* @param candidateAspectClass 候选的切面类
* @return 对应的 AspectJExpressionPointcut,如果方法没有对应的 AspectJ 注解则返回 null
*/
@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 查找方法上的 AspectJ 注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
// 如果方法没有对应的 AspectJ 注解,则返回 null
return null;
}
// 创建 AspectJExpressionPointcut
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// 设置 Pointcut 表达式
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
// 如果 beanFactory 不为空,则设置 beanFactory
ajexp.setBeanFactory(this.beanFactory);
}
// 返回 AspectJExpressionPointcut
return ajexp;
}这些源码的关键总结如下:
一. 获取所有 Advisor (getAdvisors 方法)1. 提取切面元数据:
MetadataAwareAspectInstanceFactory 中提取的。2. 装饰工厂:
LazySingletonAspectInstanceFactoryDecorator 包装原始工厂,这样可以确保切面实例只会被创建一次(懒加载)。3. 处理通知方法:
@Before、@After 等)。getAdvisor 方法,创建相应的 Advisor 对象,并将其添加到列表中。getAdvisor 方法通过解析方法上的注解来创建 AspectJExpressionPointcut,然后将其与通知方法一起封装成 InstantiationModelAwarePointcutAdvisorImpl 对象。4. 处理懒加载的切面:
SyntheticInstantiationAdvisor 到 Advisor 列表的开头,以确保在真正使用切面之前完成实例化。5. 处理引入增强:
@DeclareParents 注解)。getDeclareParentsAdvisor 方法,创建相应的 Advisor 对象,并将其添加到列表中。6. 返回所有 Advisor:
Advisor 对象的列表,这些 Advisor 将用于在目标对象上应用切面逻辑。二. 获取单个 Advisor (getAdvisor 方法)
1. 验证切面类:
2. 获取 Pointcut:
AspectJ 注解(如 @Before、@After),创建 AspectJExpressionPointcut 对象。null。3. 创建 Advisor:
AspectJExpressionPointcut 和通知方法封装成 InstantiationModelAwarePointcutAdvisorImpl 对象。Advisor 对象。三. 获取 Pointcut (getPointcut 方法)
1. 查找方法上的 AspectJ 注解:
AspectJ 注解(如 @Before、@After)。2. 创建 Pointcut:
AspectJ 注解,则创建 AspectJExpressionPointcut 对象,并设置相应的切入点表达式。beanFactory,则设置 beanFactory。3. 返回 Pointcut:
AspectJExpressionPointcut 对象,如果没有找到注解,则返回 null。简要总结
getAdvisors 方法从切面工厂中提取元数据,装饰工厂以实现懒加载,处理切面类中的通知方法和引入增强,最终返回所有的 Advisor。getAdvisor 方法根据通知方法创建相应的 Advisor,并将其与 Pointcut 结合起来。getPointcut 方法通过解析方法上的注解来创建并配置 Pointcut,用于在指定的连接点上应用通知。时序图如下:

关键步骤说明
Spring 容器发起,调用 ReflectiveAspectJAdvisorFactory 的 getAdvisors 方法。MetadataAwareAspectInstanceFactory 中提取切面类和切面名称。LazySingletonAspectInstanceFactoryDecorator 包装工厂。AspectJ 注解。AspectJExpressionPointcut,并与方法封装成 InstantiationModelAwarePointcutAdvisorImpl。SyntheticInstantiationAdvisor 到 Advisor 列表开头。DeclareParents 注解。Advisor。Advisor 的列表返回给 Spring 容器。 在 Spring AOP 中,TargetSource 是一个重要的概念,它用于描述 AOP 代理的目标对象。目标对象是被代理对象,即实际执行业务逻辑的对象。TargetSource 定义了如何获取这个目标对象以及它的生命周期管理。
TargetSource 提供了获取目标对象的机制,代理对象在执行方法调用时,通过 TargetSource 获取实际的目标对象。TargetSource 负责目标对象的生命周期管理,比如创建、缓存、销毁等。TargetSource 实现,可以支持不同的代理模式,比如单例、多例、懒加载等。常见的 TargetSource 实现
1. SingletonTargetSource:单例目标源,目标对象是单例的,每次获取的都是同一个实例。
2. PrototypeTargetSource:原型目标源,每次获取目标对象时,都会创建一个新的实例。
3. LazyInitTargetSource:懒加载目标源,目标对象只有在第一次使用时才会被创建。
核心类与方法
TargetSource 和其他 AOP 配置。AOP 代理。JdkDynamicAopProxy 和 CglibAopProxy)。AdvisedSupport 是 Spring AOP 框架中一个核心的配置类,它持有 TargetSource,以及其他关于 AOP 的配置。下面是一些关键代码片段:
public class AdvisedSupport extends ProxyConfig implements Advised {
// 持有的 TargetSource 实例
private TargetSource targetSource = EmptyTargetSource.INSTANCE;
// 设置 TargetSource
public void setTargetSource(TargetSource targetSource) {
this.targetSource = (targetSource != null ? targetSource : EmptyTargetSource.INSTANCE);
}
// 获取 TargetSource
public TargetSource getTargetSource() {
return this.targetSource;
}
// 其他相关配置和方法
}ProxyFactory 类用于创建 AOP 代理。它继承自 AdvisedSupport,所以可以直接访问 TargetSource。
相关的类用一张图说明:

代码提出来分析
/**
* 根据此工厂中的设置创建一个新的代理。
* <p>此方法可以重复调用。如果我们添加或删除接口,效果会有所不同。
* 可以添加和删除拦截器。
* <p>使用默认的类加载器:通常是线程上下文类加载器(如果代理创建需要)。
* @return 代理对象
*/
public Object getProxy() {
// 调用 createAopProxy() 方法创建 AOP 代理,然后调用其 getProxy() 方法返回代理对象
return createAopProxy().getProxy();
}
/**
* 创建一个新的 AOP 代理。子类应调用此方法来获取新的 AOP 代理,而不应直接使用 this 作为参数创建 AOP 代理。
* @return 新的 AOP 代理
*/
protected final synchronized AopProxy createAopProxy() {
// 如果代理还没有激活,则激活代理
if (!this.active) {
activate();
}
// 调用 AopProxyFactory 的 createAopProxy 方法创建新的 AOP 代理
return getAopProxyFactory().createAopProxy(this);
}
/**
* 根据 AdvisedSupport 配置创建一个 AOP 代理。此方法决定使用哪种代理实现(JDK 动态代理或 CGLIB 代理)。
**/
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 检查是否在原生镜像中执行,以及是否优化、代理目标类或没有用户提供的代理接口
if (!NativeDetector.inNativeImage() &&
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
// 获取目标类
Class<?> targetClass = config.getTargetClass();
// 如果目标类为空,抛出 AopConfigException 异常
if (targetClass == null) {
throw new AopConfigException("TargetSource 无法确定目标类: " +
"创建代理需要一个接口或目标对象。");
}
// 如果目标类是接口或代理类或 lambda 表达式,使用 JdkDynamicAopProxy
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || AopProxyUtils.isLambda(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 否则,使用 ObjenesisCglibAopProxy
return new ObjenesisCglibAopProxy(config);
} else {
// 默认使用 JdkDynamicAopProxy
return new JdkDynamicAopProxy(config);
}
} getProxy 方法是调用 createAopProxy() 方法创建 AOP 代理对象,然后调用创建的 AOP 代理对象的 getProxy() 方法返回实际的代理对象。
createAopProxy 方法首先检查代理是否已激活,如果未激活则调用 activate() 方法激活代理。调用 getAopProxyFactory().createAopProxy(this) 方法,通过 AopProxyFactory 创建新的 AOP 代理对象。
createAopProxy 方法过程如下:
AopConfigException 异常。lambda 表达式,使用 JdkDynamicAopProxy 创建代理。ObjenesisCglibAopProxy 创建代理。JdkDynamicAopProxy。下面时序图是说明 TargetSource 在 Spring AOP 中的构建和使用过程:

关键步骤说明
1. 创建并配置 AdvisedSupport 实例:
Spring 容器创建一个 AdvisedSupport 实例,并根据配置设置其属性,包括 TargetSource。2. 设置 TargetSource:
AdvisedSupport 实例中设置 TargetSource,它定义了如何获取目标对象。3. 创建 AopProxy:
Spring 容器调用 AopProxyFactory 创建 AopProxy 实例,传递 AdvisedSupport 作为配置。4. 获取配置信息:
AopProxyFactory 从 AdvisedSupport 获取创建 AopProxy 所需的配置信息。5. 根据配置创建 AopProxy 实例:
AopProxyFactory 根据 AdvisedSupport 配置决定使用哪种 AopProxy 实现(如 JdkDynamicAopProxy 或 CglibAopProxy),并创建 AopProxy 实例。6. 获取 TargetSource:
AopProxy 从 AdvisedSupport 中获取 TargetSource 实例。7. 获取目标对象:
AopProxy 调用 TargetSource 的 getTarget 方法获取实际的目标对象实例。8. 创建代理对象:
AopProxy 使用目标对象创建代理对象。9. 返回代理对象:
AopProxy 将创建的代理对象返回给 Spring 容器。10. 返回代理对象给调用者:
Spring 容器将代理对象返回给调用者。欢迎一键三连~
有问题请留言,大家一起探讨学习
----------------------Talk is cheap, show me the code-----------------------
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。