• 0
  • 0
分享
  • Spring AOP自动代理入口篇——软件测试圈
  • 北极 2021-04-29 14:04:21 字数 19513 阅读 1600 收藏 0

从本篇文章开始,我们一起来看看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 远程调用的实现,因为本地类没有远程能力,可以通过这种方式进行拦截。

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

如何激活 AOP 模块?

如何开启 Spring 的 AOP 模块,首先我们需要引入 spring-aop 和 aspectjweaver 两个模块,然后通过下面的方式开启 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 {}
}

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

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

类图

11.png

简单描述:

  • 【重点】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);
}

该方法的处理过程如下:

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

  • 将当前 Bean 保存至 earlyProxyReferences 集合(早期的代理应用对象),也就是说当这个 Bean 出现循环依赖了,在实例化后就创建了代理对象(如果有必要),可以防止后续初始化后再次创建代理对象

  • 【重点】调用 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;
}

该方法的处理过程如下:

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

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

  1. 已创建代理对象(或不需要创建),则直接返回 null,进行后续的 Bean 加载过程

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

  • 如果是 Spring 内部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 标记接口)

  • 应该跳过

  1. 通过自定义 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;
}
  • 如果 TargetSource 不为空,表示需要创建代理对象

  1. 将当前 beanName 保存至 targetSourcedBeans 集合,表示这个 Bean 已自定义生成 TargetSource 对象

  2. 调用 getAdvicesAndAdvisorsForBean(..) 方法,获取能够应用到当前 Bean 的所有 Advisor(已根据 @Order 排序),在后面进行分析?????

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

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

  5. 返回代理对象

  • 否则,直接返回 null,进行后续的 Bean 加载过程

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

上面的 4.2 和 4.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;
}

该方法的处理过程如下:

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

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

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

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

  • 直接返回 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 标记接

  • 应该跳过

  1. 调用 getAdvicesAndAdvisorsForBean(..) 方法,获取能够应用到当前 Bean 的所有 Advisor(已根据 @Order 排序),在后面进行分析?????

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

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

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

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

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

  • 返回代理对象

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

  2. 返回这个 Bean 对象

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

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

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

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

总结

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 种方法创建代理对象,这三种方法的处理过程主要分为以下两步:

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

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

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


作者:月圆

原文链接:https://www.cnblogs.com/lifullmoon/p/14677287.html


  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          •   应用场景:Allure Report报表以收集测试运行信息翔实、分类完整、显示美观受到了很多自动化测试朋友的青睐。有些企业可能没有完全集成到CICD上,也有的企业用的是Python, 这就要求我们测试人员要能灵活地根据实际状况配置Allure Report。今天介绍一下如何与pytest 结合快速生成一份报告在测试本机,期望能够为正在烦恼的自动化测试朋友提供一份帮助。(如果想配置Allure Report 在Jenkins, 您可以下载 Allure Plugin)  温馨提示:如果阅读者想按示例进行操作,您一定要具备以下的配置。   ·自动化框架: Selenium&...
            1 1 1362
            分享
          •   很多新手,不知道软件测试学习该如何开始,软件测试需要掌握哪些知识。下面是根据本人的理解,粗略整理的一个学习大纲,基本上涵盖了软件测试工程师需要掌握的全部技能,希望对刚入行或者准备学习测试的朋友提供一点指引。  1.测试基础理论  不管有没有计算机基础,测试理论的学习都是首要的,不管你的目标是功能测试、性能测试、测试开发,这些基础知识必须优先掌握。  主要包括常见的软件开发流程及模型,尤其是解敏捷开发相关知识。然后,要学习软件测试的定义、分类、测试的流程、测试用例编写方法以及缺陷(bug)的管理及生命周期。其次,要了解web端和app的常见测试点和测试方法。最后,要会编写常见的测试文档,如b...
            9 9 1091
            分享
          • 第一章 软件工程概论软件:是计算机程序、方法、规则、相关的文档以及运行计算机系统时所必需的数据的总和(狭义定义:软件=程序+数据+文档)软件的特性:软件是复杂的、软件是不可见的、软件是不断变化的和软件质量难以稳定。软件的质量特性:功能性、可靠性、易用性、效率、维护性、可移植性。软件危机:指在计算机软件的开发和维护过程中所遇到的一系列严重问题。软件危机的主要表现:对软件开发成本和进度估计常常很不准确用户对"已完成"的系统不满意的现象经常发生软件产品的质量往往靠不住软件常常是不可维护的软件成本在计算机系统总成本所占的比例逐年上升软件危机产生的主要原因:软件日益复杂和庞大软件开发...
            0 0 3146
            分享
          •   苹果在一份支持文件中宣布,它将在2023年7月26日下线"我的照片流"。这项服务已经提供了十多年,允许用户通过互联网在苹果设备上同步他们的照片。这项图片同步服务最初被称为"照片流",是在2011年WWDC期间宣布的。它可以自动从iPhone或iPad上传多达1000张最近点击的照片到iCloud。  上传的媒体在云端停留长达30天,并自动下载到使用同一苹果ID的其他设备上,包括Mac和WindowsPC。同样,当年在Mac上导入iPhoto应用的新图片也会被上传到云端,并在不同设备间同步。  最终,在上传所有照片、视频以及对媒体进行编辑的iCloud...
            0 0 863
            分享
          • 1、微信支付的流程2、微信的接口文档https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_13、新建一个spring-boot的项目4、导入需要的依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/200...
            0 0 1517
            分享
      • 51testing软件测试圈微信