死磕Spring之AOP篇 - Spring AOP自动代理(一)入口

该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读。

Spring 版本:5.1.14.RELEASE

在开始阅读 Spring AOP 源码之前,需要对 Spring IoC 有一定的了解,可查看我的 《死磕Spring之IoC篇 - 文章导读》 这一系列文章

了解 AOP 相关术语,可先查看 《Spring AOP 常见面试题) 》 这篇文章

该系列其他文章请查看:《死磕 Spring 之 AOP 篇 - 文章导读》

通过上一篇文章《Spring AOP 总览》我们对 Spring AOP 有了一个整体的认识,那么从本篇文章开始,我们一起来看看 Spring AOP 和 Spring IoC 是如何整合的,自动代理的过程做了哪些事情?

首先我们得清楚 Bean 的加载过程,整个过程中会调用相应的 BeanPostProcessor 对正在创建 Bean 进行处理,例如:

  1. 在 Bean 的实例化前,会调用 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation(..) 方法进行处理

  2. 在 Bean 出现循环依赖的情况下,会调用 SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference(..) 方法对提前暴露的 Bean 进行处理

  3. 在 Bean 初始化后,会调用 BeanPostProcessor#postProcessAfterInitialization(..) 方法对初始化好的 Bean 进行处理

Spring AOP 则是通过上面三个切入点进行创建代理对象,实现自动代理

  • 在 Spring AOP 中主要是通过第 3 种 BeanPostProcessor 创建代理对象,在 Bean 初始化后,也就是一个“成熟态”,然后再尝试是否创建一个代理对象;
  • 2 种方式是为了解决 Bean 循环依赖的问题,虽然 Bean 仅实例化还未初始化,但是出现了循环依赖,不得不在此时创建一个代理对象;
  • 1 种方式是在 Bean 还没有实例化的时候就提前创建一个代理对象(创建了则不会继续后续的 Bean 的创建过程),例如 RPC 远程调用的实现,因为本地类没有远程能力,可以通过这种方式进行拦截。

对于 Bean 的加载过程不清楚的小伙伴可以查看我的《死磕Spring之IoC篇 - 文章导读》这篇文章,或者直接查看《死磕Spring之IoC篇 - Bean 的创建过程》 这篇文章

Spring AOP 自动代理的实现主要由 AbstractAutoProxyCreator 完成,它实现了 BeanPostProcessor、SmartInstantiationAwareBeanPostProcessor 和 InstantiationAwareBeanPostProcessor 三个接口,那么这个类就是 Spring AOP 的入口,在这里将 Advice 织入我们的 Bean 中,创建代理对象。

如何激活 AOP 模块?

如何开启 Spring 的 AOP 模块,首先我们需要引入 spring-aopaspectjweaver 两个模块,然后通过下面的方式开启 AOP:

  • 添加 @EnableAspectJAutoProxy 注解
  • 添加 <aop:aspectj-autoproxy /> XML 配置

备注:在 Spring Boot 中使用 AOP 可以不需要上面两种配置,因为在 Spring Boot 中当你引入上面两个模块后,默认开启,可以看到下面这个配置类:

package org.springframework.boot.autoconfigure.aop;

@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = false)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
	public static class JdkDynamicAutoProxyConfiguration {}

	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = true)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
	public static class CglibAutoProxyConfiguration {}
}

只要存在 EnableAspectJAutoProxyAspectAdviceAnnotatedElement 四个 Class 对象,且 spring.aop.auto 配置为 true(没有配置则为 true),那么就会加载 AopAutoConfiguration 当前这个 Bean,而内部又使用了 @EnableAspectJAutoProxy 注解,那么表示开启 AOP。

至于这个注解或者 XML 配置的方式为什么就开启 AOP,是因为会引入 AbstractAutoProxyCreator 这个对象,具体怎么引入的,在后续文章进行分析😈

类图

简单描述:

  • 【重点】org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator:AOP 自动代理的抽象类,完成主要的逻辑实现,提供一些骨架方法交由子类完成
  • org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator:仅支持指定 List<String> beanNames 完成自动代理,需要指定 interceptorNames 拦截器
  • 【重点】org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator:支持从当前 Spring 上下文获取所有 Advisor 对象,存在能应用与 Bean 的 Advisor 则创建代理对象
  • org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator:仅支持获取 Spring 内部的 Advisor 对象(BeanDefinition 的角色为 ROLE_INFRASTRUCTURE
  • org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator:支持配置前缀,只能获取名称已该前缀开头的 Advisor 对象
  • 【重点】org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator:支持按照 AspectJ 的方式对 Advisor 进行排序
  • 【重点】org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator:支持从带有 @AspectJ 注解 Bean 中解析 Advisor 对象

我们主要关注上面【重点】的几个对象,因为 Sping AOP 推荐使用 AspectJ 里面的注解进行 AOP 的配置,你牢牢记住AbstractAutoProxyCreator这个自动代理类。

AbstractAutoProxyCreator

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator:AOP 自动代理的抽象类,完成主要的逻辑实现,提供一些骨架方法交由子类完成

相关属性

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {

	/** 空对象,表示不需要进行代理 */
	@Nullable
	protected static final Object[] DO_NOT_PROXY = null;

	/**
	 * 空的数组,表示需要进行代理,但是没有解析出 Advice
	 * 查看 {@link BeanNameAutoProxyCreator#getAdvicesAndAdvisorsForBean} 就知道其用途
	 */
	protected static final Object[] PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS = new Object[0];

	/** DefaultAdvisorAdapterRegistry 单例,Advisor适配器注册中心 */
	private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();

	/** 是否冻结代理对象 */
	private boolean freezeProxy = false;

	/** 公共的拦截器对象 */
	private String[] interceptorNames = new String[0];

	/** 是否将 `interceptorNames` 拦截器放在最前面 */
	private boolean applyCommonInterceptorsFirst = true;

    /** 自定义的 TargetSource 创建器 */
	@Nullable
	private TargetSourceCreator[] customTargetSourceCreators;

	@Nullable
	private BeanFactory beanFactory;

	/**
	 * 保存自定义 {@link TargetSource} 对象的 Bean 的名称
	 */
	private final Set<String> targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

	/**
	 * 保存提前创建代理对象的 Bean
	 * key:cacheKey(Bean 的名称或者 Class 对象)
	 * value:Bean 对象
	 *
	 * Spring AOP 的设计之初是让 Bean 在完全创建好后才完成 AOP 代理,如果出现了循环依赖,则需要提前(实例化后还未初始化)创建代理对象
	 * 那么需要先保存提前创建代理对象的 Bean,这样在后面可以防止再次创建代理对象
	 */
	private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);

	/**
	 * 保存代理对象的 Class 对象
	 * key:cacheKey(Bean 的名称或者 Class 对象)
	 * value:代理对象的 Class 对象(目标类的子类)
	 *
	 */
	private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<>(16);

	/**
	 * 保存是否需要创建代理对象的信息
	 * key:cacheKey(Bean 的名称或者 Class 对象)
	 * value:是否需要创建代理对象,false 表示不需要创建代理对象,true 表示已创建代理对象
	 */
	private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);
}

上面的每个属性都已经注释,先简单理解即可,具体在后面的方法可查看其用途

getEarlyBeanReference 方法

getEarlyBeanReference(Object bean, String beanName),用于处理早期暴露的对象,如果有必要的话会创建一个代理对象,该方法定义在 SmartInstantiationAwareBeanPostProcessor 中,实现如下:

/**
 * 该方法对早期对象(提前暴露的对象,已实例化还未初始化)进行处理
 * 参考 {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getEarlyBeanReference }
 *
 * @param bean     the raw bean instance
 * @param beanName the name of the bean
 * @return 早期对象(可能是一个代理对象)
 */
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
    // <1> 获取这个 Bean 的缓存 Key,默认为 Bean 的名称,没有则取其对应的 Class 对象
    Object cacheKey = getCacheKey(bean.getClass(), beanName);
    /*
     * <2> 将当前 Bean 保存至 earlyProxyReferences 集合(早期的代理应用对象)
     * 也就是说当这个 Bean 出现循环依赖了,在实例化后就创建了代理对象(如果有必要)
     */
    this.earlyProxyReferences.put(cacheKey, bean);
    // <3> 为这个 Bean 创建代理对象(如果有必要的话)
    return wrapIfNecessary(bean, beanName, cacheKey);
}

该方法的处理过程如下:

  1. 获取这个 Bean 的缓存 Key,默认为 Bean 的名称,没有则取其对应的 Class 对象
  2. 将当前 Bean 保存至 earlyProxyReferences 集合(早期的代理应用对象),也就是说当这个 Bean 出现循环依赖了,在实例化后就创建了代理对象(如果有必要),可以防止后续初始化后再次创建代理对象
  3. 【重点】调用 wrapIfNecessary(..) 方法,为这个 Bean 创建代理对象(如果有必要的话),该方法在后面分析👨‍🎓

对于 getEarlyBeanReference(..) 方法在哪被调用,可能你已经忘记了,这里来回顾一下:

// 在 AbstractAutowireCapableBeanFactory#doCreateBean 创建 Bean 的过程中,实例化后会执行下面步骤
/**
 * <3.2>
 * 创建一个 ObjectFactory 实现类,用于返回当前正在被创建的 `bean`,提前暴露,保存在 `singletonFactories` (**三级 Map**)缓存中
 *
 * 可以回到前面的 {@link AbstractBeanFactory#doGetBean#getSingleton(String)} 方法
 * 加载 Bean 的过程会先从缓存中获取单例 Bean,可以避免单例模式 Bean 循环依赖注入的问题
 */
addSingletonFactory(beanName,
        // ObjectFactory 实现类
        () -> getEarlyBeanReference(beanName, mbd, bean));

// 获取早期暴露的对象时候的处理,会调用 SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference(..) 方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() // RootBeanDefinition 不是用户定义的(由 Spring 解析出来的)
            && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
    }
    return exposedObject;
}

上面这个过程是为了处理循环依赖的问题,在 Bean 实例化后就提前暴露这个对象,如果真的出现了循环依赖,如果这个 Bean 需要进行代理,那么就不得不提前为它创建一个代理对象,虽然这个 Bean 还未初始化,不是一个“成熟态”。

关于 Spring 如何处理循环依赖的过程,如果你不熟悉可查看我的另一篇文章《死磕Spring之IoC篇 - 单例 Bean 的循环依赖处理》

postProcessBeforeInstantiation 方法

postProcessBeforeInstantiation(Class<?> beanClass, String beanName),Bean 的创建过程中实例化前置处理,也就是允许你在创建 Bean 之前进行处理。如果该方法返回的不为 null,后续 Bean 加载过程不会继续,也就是说这个方法可用于获取一个 Bean 对象。通常这里用于创建 AOP 代理对象,或者 RPC 远程调用的实现(因为本地类没有远程能力,可以通过这种方式进行拦截)。

该方法定义在 InstantiationAwareBeanPostProcessor 中,实现如下:

/**
 * 在加载 Bean 的过程中,Bean 实例化的前置处理
 * 如果返回的不是 null 则不会进行后续的加载过程,也就是说这个方法用于获取一个 Bean 对象
 * 通常这里用于创建 AOP 代理对象,返回的对象不为 null,则会继续调用下面的 {@link this#postProcessAfterInitialization} 方法进行初始化后置处理
 * 参考 {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation}
 *
 * @param beanClass the class of the bean to be instantiated
 * @param beanName  the name of the bean
 * @return 代理对象或者空对象
 */
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    // <1> 获取这个 Bean 的缓存 Key,默认为 Bean 的名称,没有则取其对应的 Class 对象
    Object cacheKey = getCacheKey(beanClass, beanName);

    // <2> 如果没有 beanName 或者没有自定义生成 TargetSource
    if (!StringUtils.hasLength(beanName) // 没有 beanName
            || !this.targetSourcedBeans.contains(beanName)) // 没有自定义生成 TargetSource
    {
        /*
         * <2.1> 已创建代理对象(或不需要创建),则直接返回 null,进行后续的 Bean 加载过程
         */
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        /*
         * <2.2>不需要创建代理对象,则直接返回 null,进行后续的 Bean 加载过程
         */
        if (isInfrastructureClass(beanClass) // 如果是 Spring 内部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 标记接口)
                || shouldSkip(beanClass, beanName)) // 应该跳过
        {
            // 将这个 Bean 不需要创建代理对象的结果保存起来
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }
    /*
     * <3> 通过自定义 TargetSourceCreator 创建自定义 TargetSource 对象
     * 默认没有 TargetSourceCreator,所以这里通常都是返回 null
     */
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    /*
     * <4> 如果 TargetSource 不为空,表示需要创建代理对象
     */
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            // <4.1> 将当前 beanName 保存至集合,表示这个 Bean 已自定义生成 TargetSource 对象
            this.targetSourcedBeans.add(beanName);
        }
        // <4.2> 获取能够应用到当前 Bean 的所有 Advisor(已根据 @Order 排序)
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        // <4.3> 创建代理对象,JDK 动态代理或者 CGLIB 动态代理
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        // <4.4> 将代理对象的 Class 对象(目标类的子类)保存
        this.proxyTypes.put(cacheKey, proxy.getClass());
        // <4.5> 返回代理对象
        return proxy;
    }
    // <5> 否则,直接返回 null,进行后续的 Bean 加载过程
    return null;
}

该方法的处理过程如下:

  1. 获取这个 Bean 的缓存 Key,默认为 Bean 的名称,没有则取其对应的 Class 对象

  2. 如果没有 beanName 或者没有自定义生成 TargetSource

    1. 已创建代理对象(或不需要创建),则直接返回 null,进行后续的 Bean 加载过程
    2. 满足下面其中一个条件表示不需要创建代理对象,则直接返回 null,并将这个 Bean 不需要创建代理对象的结果保存至 advisedBeans
      • 如果是 Spring 内部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 标记接口)
      • 应该跳过
  3. 通过自定义 TargetSourceCreator 创建自定义 TargetSource 对象,默认没有 TargetSourceCreator,所以这里通常都是返回 null

    @Nullable
    protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
        if (this.customTargetSourceCreators != null &&
                this.beanFactory != null && this.beanFactory.containsBean(beanName)) {
            for (TargetSourceCreator tsc : this.customTargetSourceCreators) {
                // 通过 TargetSourceCreator 获取 `beanName` 的自定义 TargetSource
                TargetSource ts = tsc.getTargetSource(beanClass, beanName);
                if (ts != null) {
                    return ts;
                }
            }
        }
        return null;
    }
    
  4. 如果 TargetSource 不为空,表示需要创建代理对象

    1. 将当前 beanName 保存至 targetSourcedBeans 集合,表示这个 Bean 已自定义生成 TargetSource 对象
    2. 调用 getAdvicesAndAdvisorsForBean(..) 方法,获取能够应用到当前 Bean 的所有 Advisor(已根据 @Order 排序),在后面进行分析👨‍🎓
    3. 调用 createProxy(..) 方法,创建代理对象,JDK 动态代理或者 CGLIB 动态代理,在后面进行分析👨‍🎓
    4. 将代理对象的 Class 对象(目标类的子类)保存至 proxyTypes
    5. 返回代理对象
  5. 否则,直接返回 null,进行后续的 Bean 加载过程

这里先解释一下 TargetSource,这个对象表示目标类的来源,用于获取代理对象的目标对象,上面如果存在 TargetSourceCreator,表示可以创建自定义的 TargetSource,也就需要进行 AOP 代理。默认情况下是没有 TargetSourceCreator 的,具体使用场景目前还没有接触过。

上面的 4.24.3 两个方法非常复杂,放在后面进行分析😈

同样对于 postProcessBeforeInstantiation(..) 方法在哪被调用,可能你已经忘记了,这里来回顾一下:

// 在 AbstractAutowireCapableBeanFactory#createBean 创建 Bean 的过程中,开始前会执行下面步骤
/**
 * <3> 在实例化前进行相关处理,会先调用所有 {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation}
 * 注意,如果这里返回对象不是 `null` 的话,不会继续往下执行原本初始化操作,直接返回,也就是说这个方法返回的是最终实例对象
 * 可以通过这种方式提前返回一个代理对象,例如 AOP 的实现,或者 RPC 远程调用的实现(因为本地类没有远程能力,可以通过这种方式进行拦截)
 */
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
    return bean;
}

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        // 如果 RootBeanDefinition 不是用户定义的(由 Spring 解析出来的),并且存在 InstantiationAwareBeanPostProcessor 处理器
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                 // 实例化前置处理
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    // 后置处理
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

上面过程是提供一种扩展点,可以让你在 Bean 创建之前进行相关处理,例如进行 AOP 代理,或者 RPC 远程调用的实现(因为本地类没有远程能力,可以通过这种方式进行拦截)。

关于 Spring Bean 的创建过程,如果你不熟悉可查看我的另一篇文章《死磕Spring之IoC篇 - Bean 的创建过程》

postProcessAfterInitialization 方法

postProcessAfterInitialization(@Nullable Object bean, String beanName),Bean 的初始化后置处理,在 Bean 初始化后,已经进入一个“成熟态”,那么此时就可以创建 AOP 代理对象了,如果有必要的话。

该方法定义在 BeanPostProcessor 中,实现如下:

/**
 * 在加载 Bean 的过程中,Bean 初始化的后置处理
 * 参考 {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)}
 */
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    // <1> 如果 bean 不为空则进行接下来的处理
    if (bean != null) {
        // <1.1> 获取这个 Bean 的缓存 Key,默认为 Bean 的名称,没有则取其对应的 Class 对象
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        /*
         * <1.2> 移除 `earlyProxyReferences` 集合中保存的当前 Bean 对象(如果有的话)
         * 如果 earlyProxyReferences 集合中没有当前 Bean 对象,表示在前面没有创建代理对象
         */
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            // 这里尝试为这个 Bean 创建一个代理对象(如果有必要的话)
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    // <2> 直接返回 bean 对象
    return bean;
}

该方法的处理过程如下:

  1. 如果 bean 不为空则进行接下来的处理

    1. 获取这个 Bean 的缓存 Key,默认为 Bean 的名称,没有则取其对应的 Class 对象

    2. 移除 earlyProxyReferences 集合中保存的当前 Bean 对象(如果有的话),如果 earlyProxyReferences 集合中没有当前 Bean 对象,表示在前面没有创建代理对象

      【重点】那么调用 wrapIfNecessary(..) 方法,尝试为这个 Bean 创建一个代理对象(如果有必要的话),该方法在后面分析👨‍🎓

  2. 直接返回 bean 对象

对于 postProcessAfterInitialization(..) 方法在哪被调用,可能你已经忘记了,这里来回顾一下:

// 在 AbstractAutowireCapableBeanFactory#doCreateBean#initializeBean 创建 Bean 的过程中,属性填充后会进行初始化,初始化后会执行下面的操作
/**
 * <4> **初始化**阶段的**后置处理**,执行所有 BeanPostProcessor 的 postProcessAfterInitialization 方法
 *
 * 在 {@link AbstractApplicationContext#prepareBeanFactory} 方法中会添加 {@link ApplicationListenerDetector} 处理器
 * 如果是单例 Bean 且为 ApplicationListener 类型,则添加到 Spring 应用上下文,和 Spring 事件相关
 */
if (mbd == null || !mbd.isSynthetic()) {
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {
    Object result = existingBean;
    // 遍历所有 BeanPostProcessor
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        // 初始化的后置处理,返回 `current` 处理结果
        Object current = processor.postProcessAfterInitialization(result, beanName);
        // 处理结果为空,则直接返回 `result`
        if (current == null) {
            return result;
        }
        // 否则,`result` 复制 `current`
        result = current;
    }
    return result;
}

上面这个过程在 Bean 初始化后,提供一个扩展点允许对这个 Bean 进行后置处理,此时 Bean 进入一个 “成熟态”,在这里则可以进行 AOP 代理对象的创建

关于 Spring Bean 的初始化过程,如果你不熟悉可查看我的另一篇文章《死磕Spring之IoC篇 - Bean 的创建过程》

wrapIfNecessary 方法

wrapIfNecessary(Object bean, String beanName, Object cacheKey),该方法用于创建 AOP 代理对象,如果有必要的话

上面的 getEarlyBeanReference(..)postProcessAfterInitialization(..) 方法都会调用这个方法,如下:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    /*
     * <1> 如果当前 Bean 已经创建过自定义 TargetSource 对象
     * 表示在上面的**实例化前置处理**中已经创建代理对象,那么直接返回这个对象
     */
    if (StringUtils.hasLength(beanName)
            && this.targetSourcedBeans.contains(beanName))
    {
        return bean;
    }
    // <2> `advisedBeans` 保存了这个 Bean 没有必要创建代理对象,则直接返回
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    /*
     * <3> 不需要创建代理对象,则直接返回当前 Bean
     */
    if (isInfrastructureClass(bean.getClass()) // 如果是 Spring 内部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 标记接口)
            || shouldSkip(bean.getClass(), beanName)) // 应该跳过
    {
        // 将这个 Bean 不需要创建代理对象的结果保存起来
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    // <4> 获取能够应用到当前 Bean 的所有 Advisor(已根据 @Order 排序)
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    // <5> 如果有 Advisor,则进行下面的动态代理创建过程
    if (specificInterceptors != DO_NOT_PROXY) {
        // <5.1> 将这个 Bean 已创建代理对象的结果保存至 `advisedBeans`
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // <5.2> 创建代理对象,JDK 动态代理或者 CGLIB 动态代理
        // 这里传入的是 SingletonTargetSource 对象,可获取代理对象的目标对象(当前 Bean)
        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        // <5.3> 将代理对象的 Class 对象(目标类的子类)保存
        this.proxyTypes.put(cacheKey, proxy.getClass());
        // <5.4> 返回代理对象
        return proxy;
    }

    // <6> 否则,将这个 Bean 不需要创建代理对象的结果保存起来
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    // <7> 返回这个 Bean 对象
    return bean;
}

该方法处理过程如下:

  1. 如果当前 Bean 已经创建过自定义 TargetSource 对象,表示在上面的实例化前置处理中已经创建代理对象,那么直接返回这个对象

  2. 如果 advisedBeans 保存了这个 Bean 没有必要创建代理对象,则直接返回这个对象

  3. 如果满足下面其中一个条件,表示不需要创建代理对象,则直接返回当前 Bean,并将这个 Bean 不需要创建代理对象的结果保存至 advisedBeans

    • 如果是 Spring 内部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 标记接
    • 应该跳过
  4. 调用 getAdvicesAndAdvisorsForBean(..) 方法,获取能够应用到当前 Bean 的所有 Advisor(已根据 @Order 排序),在后面进行分析👨‍🎓

  5. 如果有 Advisor,则进行下面的动态代理创建过程

    1. 将这个 Bean 已创建代理对象的结果保存至 advisedBeans

    2. 调用 createProxy(..) 方法,创建代理对象,JDK 动态代理或者 CGLIB 动态代理,在后面进行分析👨‍🎓

      注意,这里传入的是 SingletonTargetSource 对象,可获取代理对象的目标对象(当前 Bean)

    3. 将代理对象的 Class 对象(目标类的子类)保存至 proxyTypes

    4. 返回代理对象

  6. 否则,将这个 Bean 不需要创建代理对象的结果保存至 advisedBeans

  7. 返回这个 Bean 对象

到这里,getEarlyBeanReference(..)postProcessBeforeInstantiation(..)postProcessAfterInitialization(..) 三个方法的 AOP 自动代理过程主要分为两步:

  1. 调用 getAdvicesAndAdvisorsForBean(..) 方法,获取能够应用到当前 Bean 的所有 Advisor(已根据 @Order 排序)

  2. 调用 createProxy(..) 方法,根据找到的 Advisor 创建一个代理对象,JDK 动态代理或者 CGLIB 动态代理

上面的流程看起来并不复杂,看着好像就调用两个方法,不过不要被表象所迷惑,这只是冰山一角。

AOP

总结

Spring AOP 自动代理是通过实现 Spring IoC 中的几种 BeanPostProcessor 处理器,在 Bean 的加载过程中进行扩展,如果有必要的话(找到了能够应用于这个 Bean 的 Advisor)则创建 AOP 代理对象, JDK 动态代理或者 CGLIB 动态代理。

AbstractAutoProxyCreator 则是自动代理的入口,实现了三种 BeanPostProcessor 处理器,SmartInstantiationAwareBeanPostProcessor、InstantiationAwareBeanPostProcessor 和 BeanPostProcessor,实现的三个方法:

  1. getEarlyBeanReference(..):用于处理早期暴露的对象,如果有必要的话会创建一个代理对象

  2. postProcessBeforeInstantiation(..):Bean 的创建过程中实例化前置处理,允许你在创建 Bean 之前进行处理。如果该方法返回的不为 null,后续 Bean 加载过程不会继续,也就是说这个方法可用于获取一个 Bean 对象。通常这里用于创建 AOP 代理对象,或者 RPC 远程调用的实现(因为本地类没有远程能力,可以通过这种方式进行拦截)。

  3. postProcessAfterInitialization(..):Bean 的初始化后置处理,在 Bean 初始化后,已经进入一个“成熟态”,那么此时就可以创建 AOP 代理对象了,如果有必要的话。

详细过程参考上面的方法,我们主要是通过第 3 种方法创建代理对象,这三种方法的处理过程主要分为以下两步:

  1. 调用 getAdvicesAndAdvisorsForBean(..) 方法,筛选出合适的 Advisor 对象们

  2. 调用 createProxy(..) 方法,根据找到的 Advisor 创建一个代理对象,JDK 动态代理或者 CGLIB 动态代理

由于这两个步骤都比较复杂,考虑到文章的可读性,所以另起两篇文章分别分析

posted @ 2021-04-19 16:09  月圆吖  阅读(3348)  评论(2编辑  收藏  举报