• Spring 源码阅读:用于创建 AOP 代理的后处理器分析


    概述

    前面两篇文章分析了在注解配置和 XML 配置的情况下,Spring 是如何开启 AOP 特性的,经过源码分析我们知道,这两种方式的 AOP 开启,本质上都是注册了一个用来创建 AOP 代理的后处理器。

    对于在 XML 中配置切面的情况,Spring 会把创建代理的工作交给 AspectJAwareAdvisorAutoProxyCreator 后处理器来处理,而对于通过注解配置切面的情况,则交由 AnnotationAwareAspectJAutoProxyCreator 后处理器处理。

    在本文章,将对这两个后处理器进行分析,了解他们大致的工作原理。

    继承关系

    AspectJAwareAdvisorAutoProxyCreator 和 AnnotationAwareAspectJAutoProxyCreator 两个后处理器的继承关系,在前两篇文章中已经了解过了,这里我们再做简单的回顾。

    从上图中可以知道,这两个类是直接继承的父子类,他们有很多共同继承的类和实现的接口,可以推测出他们的工作逻辑有很大一部分是相同的。

    由于他们是作为后处理器注册到 Spring 容器中的,因此,他们完成 AOP 代理创建的逻辑,一定是在后处理器的方法中。从上图中看到,他们共实现了三个后处理器的接口,接下来,我们再看这三个接口中定义的方法。

    实现接口

    先看看这三个接口都定义了哪些方法。

    既然后处理器的作用要生成一个代理对象,那么,我们就应该去分析后处理器中可以修改被处理的 Bean 对象的处理方法,再上图中罗列的方法中有以下这些:

    • postProcessBeforeInstantiation方法可以在 Spring 实例化 Bean 对象之前,创建一个 Bean 对象。
    • postProcessBeforeInitialization方法可以在 Bean 的初始化方法被执行前,修改 Bean 对象。
    • postProcessAfterInitialization方法可以在 Bean 的初始化方法被执行前,修改 Bean 对象。

    以上三个方法,都可能在执行的过程中,将当前的 Bean 对象,修改为新创建的代理对象。因此,接下来,我们需要从两个后处理器中找到这三个方法的实现逻辑。

    不过,在源码中可以发现,这两个后处理器的后处理方法,都是在它们共同的父类 AbstractAutoProxyCreator 中实现的,所以,我们之后只需要分析 AbstractAutoProxyCreator 类中实现的处理方法就行了。并且,postProcessBeforeInitialization方法的实现是一个没有任何处理逻辑的默认实现,我们接下来从postProcessBeforeInstantiationpostProcessAfterInitialization两个方法中分析自动创建代理的逻辑。

    代理创建的原理

    下面从 AbstractAutoProxyCreator 的源码中,找到这两个方法进行分析。

    postProcessBeforeInstantiation

    先看postProcessBeforeInstantiation方法

    1. @Override
    2. public Object postProcessBeforeInstantiation(Class beanClass, String beanName) {
    3. Object cacheKey = getCacheKey(beanClass, beanName);
    4. if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
    5. if (this.advisedBeans.containsKey(cacheKey)) {
    6. return null;
    7. }
    8. if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
    9. this.advisedBeans.put(cacheKey, Boolean.FALSE);
    10. return null;
    11. }
    12. }
    13. // Create proxy here if we have a custom TargetSource.
    14. // Suppresses unnecessary default instantiation of the target bean:
    15. // The TargetSource will handle target instances in a custom fashion.
    16. TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    17. if (targetSource != null) {
    18. if (StringUtils.hasLength(beanName)) {
    19. this.targetSourcedBeans.add(beanName);
    20. }
    21. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
    22. Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
    23. this.proxyTypes.put(cacheKey, proxy.getClass());
    24. return proxy;
    25. }
    26. return null;
    27. }
    28. 复制代码

    方法的核心是后半部分的if语句块,在if语句块之前,通过getCustomTargetSource获取了当前 Bean 对象的自定义 TargetSource。TargetSource 指的是,Spring 创建的代理在调用目标方法时候要查找的目标来源,在创建代理对象时,当前的 Bean 对象,会被封装成一个 TargetSource 交给代理类,用于找到被增强的对象本身。

    通常情况下,我们不会自定义 TargetSource,因此,这个方法并不是我们要找的创建代理的地方。

    postProcessAfterInitialization

    接下来,找到postProcessAfterInitialization方法。

    1. @Override
    2. public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    3. if (bean != null) {
    4. Object cacheKey = getCacheKey(bean.getClass(), beanName);
    5. if (this.earlyProxyReferences.remove(cacheKey) != bean) {
    6. return wrapIfNecessary(bean, beanName, cacheKey);
    7. }
    8. }
    9. return bean;
    10. }
    11. 复制代码

    这个方法是在 Bean 实例被执行初始化操作后被调用的,因此方法可以通过参数拿到 Bean 实例对象本身,以及 Bean 的名称。

    首先,确保了 Bean 不为空之后,通过getCacheKey方法获得了一个缓存 Key。这个方法在刚刚的postProcessBeforeInstantiation方法中也见过,我们来看一下这个方法。

    1. protected Object getCacheKey(Class beanClass, @Nullable String beanName) {
    2. if (StringUtils.hasLength(beanName)) {
    3. return (FactoryBean.class.isAssignableFrom(beanClass) ?
    4. BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);
    5. }
    6. else {
    7. return beanClass;
    8. }
    9. }
    10. 复制代码

    方法中判断了 Bean 的名称是否为空,如果不为空,则根据当前的 Bean 是不是一个 FactoryBean 来返回带或者不带工厂前缀的 Bean 名称,如果 Bean 的名称为空,则直接返回 Bean 得类型本身。

    这个方法的目的是获得一个缓存 Key,用于 AbstractAutoProxyCreator 中的缓存容器。

    回到postProcessAfterInitialization方法中,接着,从earlyProxyReferences集合中,移除当前 Bean 对象对应的缓存 Key 保存的内容。那这个集合中存放了什么呢?在 AbstractAutoProxyCreator 源码中,除了这里,只有一处操作了earlyProxyReferences集合,而且是put操作,在另外一个方法中。

    1. @Override
    2. public Object getEarlyBeanReference(Object bean, String beanName) {
    3. Object cacheKey = getCacheKey(bean.getClass(), beanName);
    4. this.earlyProxyReferences.put(cacheKey, bean);
    5. return wrapIfNecessary(bean, beanName, cacheKey);
    6. }
    7. 复制代码

    这其实也是一个后处理器方法,之所以在寻找创建代理逻辑的时候没有考虑这个方法,是因为这个方法是在获取早期 Bean 对象的时候被调用的,也就是说,它不一定会被调用,而且调用的时机也不确定。在方法中,通过缓存 Key 向earlyProxyReferences集合中存放了早期的代理引用,方法最后返回了调用wrapIfNecessary方法的结果,这个方法我们稍后介绍。

    再次回到postProcessBeforeInstantiation中,如果从earlyProxyReferences移除的内容,并不是 Bean 本身,则执行wrapIfNecessary方法并将结果作为后处理方法的结果返回。

    wrapIfNecessary 方法

    到这里,我们就需要看wrapIfNecessary方法,从名字就可以看出,它的作用是在必要的时候,对 Bean 对象进行包装,并且包装好的结果会作为容器中 Bean 的对象。因此,这个方法就是用来创建 Bean 对象代理的方法。

    1. // org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
    2. protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    3. if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
    4. return bean;
    5. }
    6. if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    7. return bean;
    8. }
    9. if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    10. this.advisedBeans.put(cacheKey, Boolean.FALSE);
    11. return bean;
    12. }
    13. // Create proxy if we have advice.
    14. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    15. if (specificInterceptors != DO_NOT_PROXY) {
    16. this.advisedBeans.put(cacheKey, Boolean.TRUE);
    17. Object proxy = createProxy(
    18. bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    19. this.proxyTypes.put(cacheKey, proxy.getClass());
    20. return proxy;
    21. }
    22. this.advisedBeans.put(cacheKey, Boolean.FALSE);
    23. return bean;
    24. }
    25. 复制代码

    在判断了一些不需要在此处进行包装处理的情况后,进入了创建代理的逻辑,根据需不需要增强处理,返回创建好的代理对象,或者原本的 Bean 对象本身。

    这部分逻辑,放到之后的文章来分析。

    总结

    本文分析了用于创建 AOP 代理对象的后处理器,主要是 AbstractAutoProxyCreator 类中的后处理方法。从它实现的后处理器接口中定义的方法中,找到了用于创建 AOP 代理的逻辑是在postProcessBeforeInstantiation方法中,也就是 AOP 代理是 Bean 执行完初始化逻辑之后创建的。

  • 相关阅读:
    初学Vue(全家桶)-第19天(vue3):计算属性、监视属性、vue3生命周期
    高分植物线粒体研究:揭示棉花细胞质雄性不育的花粉败育机制
    codeforces每日5题(均1700)-第五天
    vue2入门教程
    《痞子衡嵌入式半月刊》 第 49 期
    Golang-GJSON 快速而简单的方法来从 json 文档获取值
    Android 模拟点击
    Avalonia中的自绘控件
    [附源码]Python计算机毕业设计SSM奖助学金评审系统(程序+LW)
    JavaWeb——JavaScript
  • 原文地址:https://blog.csdn.net/m0_73311735/article/details/127444646