Spring AOP原理-AOP代理的底层核心后置处理器

从 0 开始深入学习 Spring 专栏目录总览

有了前面的思路,下面我们就可以来研究 AOP 真正的底层原理了。要研究这个原理,首先咱要从开启 AOP 的核心说起,那就是 @EnableAspectJAutoProxy 注解,

1. @EnableAspectJAutoProxy的作用

翻开 @EnableAspectJAutoProxy 注解的源码,可以发现它 @Import 了一个注册器:

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;
    boolean exposeProxy() default false;
}

1.1 AspectJAutoProxyRegistrar与后置处理器

这个注册器还挺有来头,咱点进去看一眼它的文档注释,会发现它已经把核心的后置处理器给说出来了:

Registers an AnnotationAwareAspectJAutoProxyCreator against the current BeanDefinitionRegistry as appropriate based on a given @EnableAspectJAutoProxy annotation.

根据给定的 @EnableAspectJAutoProxy 注解,根据当前 BeanDefinitionRegistry 在适当的位置注册 AnnotationAwareAspectJAutoProxyCreator 。

由此可知,AOP 的核心后置处理器是 AnnotationAwareAspectJAutoProxyCreator 。

先把它放在一边,咱先了解一下 AspectJAutoProxyRegistrar 是在什么时机下注册 AnnotationAwareAspectJAutoProxyCreator 的。

1.2 AspectJAutoProxyRegistrar注册后置处理器的时机

由于 AspectJAutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar 接口,所以我们可以直接找到 registerBeanDefinitions 方法,去寻找注册的逻辑。

public void registerBeanDefinitions(
        AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    // 核心注册后置处理器的动作
    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

    // 解析@EnableAspectJAutoProxy的属性并配置
    AnnotationAttributes enableAspectJAutoProxy =
            AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
    if (enableAspectJAutoProxy != null) {
        if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
        }
        if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
            AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
        }
    }
}

合着第一句就明示了它要注册后置处理器,也就是代理的创建器了。而这个方法也指明了它要注册的 bean 的类型就是 AnnotationAwareAspectJAutoProxyCreator :

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
    return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
        BeanDefinitionRegistry registry, @Nullable Object source) {
    // 此处已指定类型
    return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

再往下,就是根据这个类型,构造 BeanDefinition ,并注册进 BeanDefinitionRegistry 的动作了,逻辑相对简单,小伙伴们扫一眼就可以了:

private static BeanDefinition registerOrEscalateApcAsRequired(
        Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

    if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
        BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
        if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
            int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
            int requiredPriority = findPriorityForClass(cls);
            if (currentPriority < requiredPriority) {
                apcDefinition.setBeanClassName(cls.getName());
            }
        }
        return null;
    }

    // 构造BeanDefinition,注册进BeanDefinitionRegistry
    RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
    beanDefinition.setSource(source);
    beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
    beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
    return beanDefinition;
}

逻辑还是简单吧,经过 IOC 部分的洗礼,这些底层看起来是不是也就轻松许多了呢?

下面我们来着重研究这个核心的后置处理器,也就是代理对象的创建器 AnnotationAwareAspectJAutoProxyCreator 。

2. AnnotationAwareAspectJAutoProxyCreator

这么重要的 API ,javadoc 中一定有对它的描述吧,咱先来看一眼:

AspectJAwareAdvisorAutoProxyCreator subclass that processes all AspectJ annotation aspects in the current application context, as well as Spring Advisors. Any AspectJ annotated classes will automatically be recognized, and their advice applied if Spring AOP’s proxy-based model is capable of applying it. This covers method execution joinpoints. If the <aop:include> element is used, only @AspectJ beans with names matched by an include pattern will be considered as defining aspects to use for Spring auto-proxying. Processing of Spring Advisors follows the rules established in org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.

它是 AspectJAwareAdvisorAutoProxyCreator 的子类,用于处理当前 ApplicationContext 中的所有基于 AspectJ 注解的切面,以及 Spring 原生的 Advisor 。

如果 Spring AOP 基于代理的模型能够应用任何被 @AspectJ 注解标注的类,那么它们的增强方法将被自动识别。这涵盖了方法执行的切入点表达式。

如果使用 <aop:include> 元素,则只有名称与包含模式匹配的被 @AspectJ 标注的 bean 将被视为定义要用于 Spring 自动代理的方面。

Spring 中内置的 Advisor 的处理遵循 AbstractAdvisorAutoProxyCreator 中建立的规则。

拆解看来,javadoc 中解释的核心内容是,AnnotationAwareAspectJAutoProxyCreator 它兼顾 AspectJ 风格的切面声明,以及 SpringFramework 原生的 AOP 编程。

2.1 AnnotationAwareAspectJAutoProxyCreator的继承结构

借助 IDEA ,可以很清楚的看到 AnnotationAwareAspectJAutoProxyCreator 的继承结构,以及它其中的重要核心:

Spring AOP原理-AOP代理的底层核心后置处理器

注意看最顶层的接口,它实现了几个重要的接口:

  • BeanPostProcessor :用于在 postProcessAfterInitialization 方法中生成代理对象
  • InstantiationAwareBeanPostProcessor :拦截 bean 的正常 doCreateBean 创建流程
  • SmartInstantiationAwareBeanPostProcessor :提前预测 bean 的类型、暴露 bean 的引用( AOP 、循环依赖等,太过于复杂,此处不作解释)
  • AopInfrastructureBean :实现了该接口的 bean 永远不会被代理(防止套娃)

除此之外,咱们一定要注意到它最开始的抽象实现类是 AbstractAutoProxyCreator ,它也是极度重要的!咱后面的不少源码分析中都会遇到它的。

2.2 AnnotationAwareAspectJAutoProxyCreator的初始化时机

既然在 AspectJAutoProxyRegistrar 中已经把 AnnotationAwareAspectJAutoProxyCreator 的 BeanDefinition 注册到 BeanDefinitionRegistry 中了,那么接下来的后置处理器初始化部分,它一定会被创建,而这个时机我们在前面 IOC 原理部分也讲过了,咱这里回顾一下:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // ......
        try {
            postProcessBeanFactory(beanFactory);
            invokeBeanFactoryPostProcessors(beanFactory);
            // 6. 注册、初始化BeanPostProcessor
            registerBeanPostProcessors(beanFactory);
            initMessageSource();
            initApplicationEventMulticaster();
            // ......
    }
}

这里面那个超级长的方法,还有印象吧!源码咱就不贴了,主要能让小伙伴们回忆起来就好。

注意一个小细节,AnnotationAwareAspectJAutoProxyCreator 实现了 Ordered 接口,它会提前于普通 BeanPostProcessor 创建,那是不是就代表着普通的 BeanPostProcessor 也会被 AOP 代理呢?答案是肯定的,小伙伴们可以自行测试一下。

2.3 AnnotationAwareAspectJAutoProxyCreator的作用时机

那既然 ApplicationContext 的 refresh 方法中,第 6 步 registerBeanPostProcessors 方法把 AnnotationAwareAspectJAutoProxyCreator 初始化好了,接下来的 bean 就应该都会被它干预了。咱以 com.linkedbear.spring.aop.b_aspectj 中的示例来看,FinanceService 对象的创建流程中 AnnotationAwareAspectJAutoProxyCreator 如何插入干预的。

2.3.1 getBean → doCreateBean

bean 的创建流程咱前面 IOC 原理部分已经学过了,从 getBean 开始,依次是 doGetBean 、createBean 、doCreateBean ,在 doCreateBean 方法中会真正的创建对象、属性赋值、依赖注入,以及初始化流程的执行。等 bean 本身的初始化流程全部执行完毕后,就该 BeanPostProcessor 的 postProcessAfterIntialization 方法了,这些咱都很熟悉。

不过,在这之前有一个小插曲,是 createBean 到 doCreateBean 这个动作中还有一个 InstantiationAwareBeanPostProcessor 的拦截初始化动作,咱需要来看一下。

2.3.2 AnnotationAwareAspectJAutoProxyCreator#postProcessBeforeInstantiation

源码不是特别长,我们可以简单的来看一下这里面发生的核心动作:

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    Object cacheKey = getCacheKey(beanClass, beanName);

    // 决定是否要提前增强当前bean
    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        // 被增强过的bean不会再次被增强
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        // 基础类型的bean不会被提前增强、被跳过的bean不会被提前增强
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }

    // 原型bean的额外处理:TargetSource
    // 此处的设计与自定义TargetSource相关,单实例bean必定返回null
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    return null;
}

纵读下来,这里面的逻辑其实并不复杂,甚至还蛮容易理解的,这里面涉及到几个小概念咱在这里解释一下。

2.3.2.1 InfrastructureClass

这个基础类型,可能小伙伴们不大理解这玩意是个啥,咱可以点进去看看:

protected boolean isInfrastructureClass(Class<?> beanClass) {
    return (super.isInfrastructureClass(beanClass) ||
            (this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass)));
}

protected boolean isInfrastructureClass(Class<?> beanClass) {
    boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
            Pointcut.class.isAssignableFrom(beanClass) ||
            Advisor.class.isAssignableFrom(beanClass) ||
            AopInfrastructureBean.class.isAssignableFrom(beanClass);
    // logger ......
    return retVal;
}

得了,合着它说的这些基础类型,是切面、切入点、增强器等等的对象!那一切就解释的过去了,一个切入点的对象包装怎么会被 AOP 代理呢?它是作为 AOP 底层非常重要的组成成员,它不应该参与到具体的被增强对象中。

2.3.2.2 被跳过的bean?

这个被跳过的 bean ,似乎在之前我们学习 AOP 的过程中一直没有接触过,它是什么意思呢?咱可以先进到源码中看看:

// AspectJAwareAdvisorAutoProxyCreator
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    // 加载增强器
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    for (Advisor advisor : candidateAdvisors) {
        // 逐个匹配,如果发现当前bean的名称与增强器的名称一致,则认为
        if (advisor instanceof AspectJPointcutAdvisor &&
                ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
            return true;
        }
    }
    return super.shouldSkip(beanClass, beanName);
}

// AbstractAutoProxyCreator
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    // 检查beanName代表的是不是原始对象(以.ORIGINAL结尾)
    return AutoProxyUtils.isOriginalInstance(beanName, beanClass);
}

简单的用注释一标,小伙伴们也不难理解这段逻辑吧,它要看看当前对象的名称是不是有跟增强器的名称撞车的,或者说它是不是一个还没有经过任何代理的原始对象。对于一般情况而言,我们构造的 bean 根本就不可能带有 .ORIGINAL 的后缀,所以这个地方相当于判断当前创建的 bean 是否名称与增强器撞车。

这里咱简单说下增强器的概念。一个 Advisor 可以视为一个切入点 + 一个通知方法的结合体,对于 Aspect 切面类中定义的通知方法,方法体 + 方法上的通知注解就可以看做一个 Advisor 增强器。更多相关的解释,咱放到下一章再研究。

至于上面的 findCandidateAdvisors 方法,里面的逻辑有点复杂,咱也放到下一章再研究。

不过在此 Debug 的时候,可以发现 findCandidateAdvisors 方法执行完成后,获取到了 5 个增强器,也都是在 Logger 类中定义的那 5 个通知方法:

Spring AOP原理-AOP代理的底层核心后置处理器

(最后一个名太长了,实际上是 afterThrowing 的通知,引用的通用切入点表达式罢了。。。)

2.3.2.3 TargetSource?

这个概念咱之前在 IOC 部分没有见到过,当然它也不是 IOC 的东西。。。这个概念咱也是放到下一章再解释吧,这里咱可以先简单说一下,AOP 的代理其实不是代理的目标对象本身,而是目标对象包装后的 TargetSource 对象。至于为什么它会这么做,咱下一章也会展开解释的。

2.3.3 AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInitialization

前面的拦截判断结束后,AnnotationAwareAspectJAutoProxyCreator 再发挥作用就要等到最后一步的 postProcessAfterInitialization 方法了,这里面就是真正的生成代理对象。方法的实现很简单,咱跳转进来看一下:

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            // 核心:构造代理
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

小小的前戏后,最关键的动作是中间的 wrapIfNecessary 方法。

这个动作从方法名上就可以很容易的理解了,如果有必要的话,给这个对象包装生成代理对象。下面进入到源码的部分(小伙伴们只需要关注标注有注释的部分即可):

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    // 如果上面的判断都没有成立,则决定是否需要进行代理对象的创建
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 创建代理对象的动作
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

所以由此可见,创建代理对象的核心动作其实就三个步骤:

  1. 判断决定是否是不会被增强的 bean
  2. 根据当前正在创建的 bean 去匹配增强器
  3. 如果有增强器,创建 bean 的代理对象

这里咱只是简单地看一下流程,具体的创建代理对象的动作,咱放到第 50 章再研究。

【到这里咱先整体的对 AOP 中的核心注解,以及后置处理器 AnnotationAwareAspectJAutoProxyCreator 有一个整体的认识,小伙伴们先把这部分消化好吧。接下来的两章,咱就要来具体的研究几个重要的环节了】

免责声明:
1.本站所有内容由本站原创、网络转载、消息撰写、网友投稿等几部分组成。
2.本站原创文字内容若未经特别声明,则遵循协议CC3.0共享协议,转载请务必注明原文链接。
3.本站部分来源于网络转载的文章信息是出于传递更多信息之目的,不意味着赞同其观点。
4.本站所有源码与软件均为原作者提供,仅供学习和研究使用。
5.如您对本网站的相关版权有任何异议,或者认为侵犯了您的合法权益,请及时通知我们处理。
火焰兔 » Spring AOP原理-AOP代理的底层核心后置处理器