¡Texto largo de mil palabras! Te llevará a explorar el proceso de carga de Bean

Este artículo se basa en Spring Boot 3.0.0 (Spring 6.0.2) y Bean hace referencia a Singleton Bean.

Hablando macroscópicamente, el proceso de carga del Bean tiene aproximadamente tres etapas, que son la creación de instancias createBeanInstance(), el llenado de atributos populateBean() y la inicialización initializeBean() ¡Cuando se completa el proceso de carga del Bean, el Bean está listo para usar! Explorar el proceso de carga de Bean es un viaje muy doloroso, ¿estás listo?

get_bean_overview.png

1 escrito al frente

Para que el contenedor Spring IoC complete correctamente el proceso de carga del Bean, debe haber un modelo de datos para transportar los metadatos de configuración del Bean. Los metadatos de configuración pueden decirle al contenedor Spring IoC cómo crear una instancia de Bean , cuándo crear una Instancia de Bean y los detalles del ciclo de vida del Bean . Y otra información, este modelo de datos es la BeanDefinitioninterfaz, entre sus muchas clases de implementación, ¡RootBeanDefinition es la más utilizada!

En Spring Boot, BeanDefinition se puede clasificar en dos categorías: una es declarada por los desarrolladores y la otra es declarada por componentes de inicio oficiales y de terceros . Por supuesto, estas dos BeanDefinition generalmente se declaran a través de anotaciones. Para cargar estas dos Definiciones de Bean, Spring Boot primero completará un proceso de carga de Bean llamado org.springframework.context.annotation.internalConfigurationAnnotationProcessor type . ConfigurationClassPostProcessorConfigurationClassPostProcessor implementa la BeanDefinitionRegistryPostProcessorinterfaz.

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry);
}
复制代码

BeanDefinitionRegistryPostProcessor se hereda de la BeanFactoryPostProcessorinterfaz, que es un punto de extensión de Spring IoC extremadamente importante.

public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);
}
复制代码

BeanFactoryPostProcessor se usa a menudo para interactuar con BeanDefinition en lugar de instancias de Bean, porque cuando postProcessBeanFactory()se ejecuta el método, solo completa la carga de todas las BeanDefinitions, y el Bean aún no se ha instanciado. Podemos reemplazar completamente el valor del atributo beanClass de una instancia de BeanDefinition con la instancia de Clase generada a través de BeanFactoryPostProcessor CGLIB, de modo que la instancia de Bean generada a través de la instancia de BeanDefinition se mejore más adelante.

当执行到 ConfigurationClassPostProcessor 中的postProcessBeanDefinitionRegistry()方法时,Spring Boot 已经提前将由@SpringBootApplication注解标注的启动类注册到了BeanDefinitionRegistry中去,那么 ConfigurationClassPostProcessor 会根据这个启动类来挖掘出所有的 BeanDefinition,接着将它们注册到 BeanDefinitionRegistry 中。

为什么一个由 @SpringBootApplication 注解标注的启动类可以衍生出全部的 BeanDefinition 呢?因为它头上有三个重要的元注解,分别是:@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan。其中,@ComponentScan 注解用于衍生出 classpath 下特定包名内的 BeanDefinition,一般这个包名就是 Spring Boot 启动类所在的包名,这也正是为什么启动类总是处于顶级包名下的答案;而 @EnableAutoConfiguration 注解则用于衍生出官方及第三方起步依赖组件中的 BeanDefinition,如果没有这个注解,那么一切官方及第三方 starter 组件都会趴窝。

继续回到 ConfigurationClassPostProcessor 中来。限于篇幅这里仅放出其核心外围源码,如下所示。其中,postProcessBeanDefinitionRegistry() 方法是先于 postProcessBeanFactory() 方法执行的。

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor {
    /**
     * Derive further bean definitions from the configuration classes in the registry.
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        processConfigBeanDefinitions(registry);
    }

    /**
     * Prepare the Configuration classes for servicing bean requests at runtime
     * by replacing them with CGLIB-enhanced subclasses.
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        enhanceConfigurationClasses(beanFactory);
        beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
    }
}
复制代码

1.1 postProcessBeanDefinitionRegistry()

postProcessBeanDefinitionRegistry() 方法无疑是 ConfigurationClassPostProcessor 中最为核心的内容,它可以将那些由开发人员和起步依赖组件中所声明的 BeanDefinition 全部加载出来,并将其注册到 BeanDefinitionRegistry 中去。

Spring 提供了一个 ConfigurationClass类,用于抽象那些由 @Configuration 注解标记的配置类。metadata 属性用于标识配置类头上的注解元数据;beanMethods 属性用于收集配置类中由 @Bean 注解标识的方法;importedBy 用于收集当前配置类是由哪些配置类通过 @Import 注解引入的;importedResources 属性用于收集当前配置类通过 @ImportResource 注解所引入的包含若干 Bean 定义信息的 XML 文件;importBeanDefinitionRegistrars 属性用于收集当前配置类通过 @Import 注解引入的 ImportBeanDefinitionRegistrar。

public final class ConfigurationClass {
    private final AnnotationMetadata metadata;
    private final Resource resource;
    private String beanName;
    private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1);
    private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();
    private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
            new LinkedHashMap<>();
    private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
            new LinkedHashMap<>();
}			
复制代码

第一个 ConfigurationClass 实例就是 Spring Boot 的启动类!ConfigurationClassPostProcessor 会委托ConfigurationClassParser来解析 ConfigurationClass 实例以填充其属性,而一个 ConfigurationClass 实例可能衍生出若干个 ConfigurationClass 实例,最终这些 ConfigurationClass 实例会被保存在 ConfigurationClassParser 中的成员变量 configurationClasses 中,然后 ConfigurationClassPostProcessor 会委派ConfigurationClassBeanDefinitionReader 负责将每一个 ConfigurationClass 实例中所蕴含的 BeanDefinition 加载出来。

相较于 BeanDefinitionReader 对 BeanDefinition 的加载,ConfigurationClassParser 对 ConfigurationClass 的解析更为吸引人,这一过程涉及对nested member class@PropertySource@ComponentScan@Import@ImportResource@Beandefault methods on interfaces 这七个目标的解析。

  • nested member class 指的是当前 ConfigurationClass 的嵌套成员静态配置类,这些配置类的头上如果有 @Component、@ComponentScan、@Import、和 @ImportResource 这四种注解任意一种标记,或者其包含由 @Bean 注解标记的方法,那么 ConfigurationClassParser 会将其封装为一个 ConfigurationClass 实例,然后对其进行递归解析。

  • @PropertySource 注解常用于引入一个或多个外部配置源文件,ConfigurationClassParser 会将每一个外部配置源文件封装为一个PropertySource实例,然后直接将其塞进Environment中。

  • 对于 @ComponentScan 注解,ConfigurationClassParser 首先委派 ComponentScanAnnotationParser 进行扫描。具体地,ComponentScanAnnotationParser 会根据 @ComponentScan 注解中 basePackages 与 basePackageClasses 这俩属性来探测出所要扫描的包名,如果没有获取到,就根据 @ComponentScan 注解所依附宿主类的包名作为扫描目标;然后将目标包下所有由 @Component 注解标注的类扫描出来并封装为 BeanDefinition 实例,接着逐个将 BeanDefinition 实例注册到 BeanDefinitionRegistry 中。

  • @Import 注解用于引入外部配置类,外部配置类可以是由 @Configuration 注解标记的常规配置类,也可以是 ImportSelector 和 ImportBeanDefinitionRegistrar 接口的实现类。processImports() 方法正是 ConfigurationClassParser 处理这三类目标的核心逻辑所在。其主要逻辑为:1) 如果引入的是 ImportSelector,则递归调用 processImports() 方法;2) 如果引入的是 DeferredImportSelector,则延迟处理;3) 如果引入的是 ImportBeanDefinitionRegistrar,则填充当前 ConfigurationClass 实例中的 importBeanDefinitionRegistrars 属性;4) 如果引入的是普通 @Configuration 配置类,则构建一个新的 ConfigurationClass 实例然后递归解析该 ConfigurationClass 实例。

  • @ImportResource 注解常用于引入一个或多个包含若干 Bean 定义信息的 XML 文件。一般大家是用不到这个注解的,但有些老的模块可能依然是通过 XML 文件来声明 Bean 定义信息,那么 @ImportResource 注解恰好提供了这种兼容能力。ConfigurationClassParser 正是在这里填充当前 ConfigurationClass 实例的 importedResources 属性。

  • 对于方法级的 @Bean 注解,ConfigurationClassParser 会为其封装为 BeanMethod 实例,然后将其回填到当前 ConfigurationClass 实例的 beanMethods 属性中。

  • default methods on interfaces 指的是 Java 8 接口中由default关键字修饰的默认方法。ConfigurationClassParser 会获取当前 ConfigurationClass 所实现的接口,然后探测出接口中所有 @Bean 方法,依然是填充当前 ConfigurationClass 实例的 beanMethods 属性。

1.2 postProcessBeanFactory()

当执行到 postProcessBeanFactory() 方法,这意味着所有的 BeanDefinition 已经完成了加载,它们都安静地躺在 BeanDefinitionRegistry 中。 而enhanceConfigurationClasses()方法是 postProcessBeanFactory() 方法中的唯一逻辑,咱们一起来瞅瞅它干了啥吧。

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor {
    public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
        Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
        for (String beanName : beanFactory.getBeanDefinitionNames()) {
            BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
            Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
            if ("full".equals(configClassAttr)) {
                configBeanDefs.put(beanName, abd);
            }
        }
        if (configBeanDefs.isEmpty()) {
            return;
        }
        ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
        for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
            AbstractBeanDefinition beanDef = entry.getValue();
            // Set enhanced subclass of the user-specified bean class
            Class<?> configClass = beanDef.getBeanClass();
            Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
            if (configClass != enhancedClass) {
                beanDef.setBeanClass(enhancedClass);
            }
        }
    }
}
复制代码

代码不多,理解起来很容易。遍历所有 BeanDefinition 实例,将所有包含 key 为 ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE、value 为 full 的 BeanDefinition 实例 收集到局部变量 configBeanDefs 中,然后使用 CGLIB 生成全新的 Class 实例并替换 BeanDefinition 实例的 beanClass 属性值,后续这些 Bean 均将会被代理类增强。

以 key 为 ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE、value 为 full 的键值对儿是啥时候塞到 BeanDefinition 实例的 attribute 中去的呢?当然是在 postProcessBeanDefinitionRegistry() 方法中塞进去的,主要内容如下。

public abstract class ConfigurationClassUtils {
    public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
        String className = beanDef.getBeanClassName();
        if (className == null || beanDef.getFactoryMethodName() != null) {
            return false;
        }
        AnnotationMetadata metadata;
        if (beanDef instanceof AnnotatedBeanDefinition
                && className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
            metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
        } else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
            Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
            if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
                    BeanPostProcessor.class.isAssignableFrom(beanClass) ||
                    AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
                    EventListenerFactory.class.isAssignableFrom(beanClass)) {
                return false;
            }
            metadata = AnnotationMetadata.introspect(beanClass);
        } else {
            MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
            metadata = metadataReader.getAnnotationMetadata();
        }
        Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
        if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
        } else if (config != null || isConfigurationCandidate(metadata)) {
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
        } else {
            return false;
        }
        Integer order = getOrder(metadata);
        if (order != null) {
            beanDef.setAttribute(ORDER_ATTRIBUTE, order);
        }
        return true;
    }
}
复制代码

忽略 根据 BeanDefinition 获取其 AnnotationMetadata 的逻辑,从上面代码中,我们可以很轻松地总结出以下规律:

  1. 若 @Configuration 注解中 proxyBeanMethods 属性值为 true,则执行 beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, "full");

  2. 若 @Configuration 注解中 proxyBeanMethods 属性值为 false,则执行 beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, "lite")。

经过第一章节的分析,我们大致了解了 BeanDefinition 的加载逻辑,接下来将会面临更大的挑战,就是对 Bean 加载流程的探索。

2 实例化

BeanFactory是 Spring 针对 IoC 容器提供的最顶级抽象接口,其主要用于加载 Bean。众所周知,相较于 BeanFactory,ApplicationContext拥有更多的拓展功能,因此后者在企业级应用中更为常用,但今天笔者想给大家介绍 BeanFactory 的另一个拓展,即AutowireCapableBeanFactory。AutowireCapableBeanFactory 提供了两个重要的方法,分别是:createBean()autowireBean()。createBean() 方法可以用于构建一个不受 IoC 容器纳管的 Bean 实例,而且在实例化 Bean 之后,也会进行 populateBean() 和 initializeBean() 操作;而 autowireBean() 方法就更为有用了,它可以为那些头上没有 stereotype 注解的普通类注入 IoC 容器中的单例 Bean,这很酷对不对?

回归正题!Bean 加载的统一入口位于AbstractBeanFactory中的getBean()方法处,熟悉 Spring 的朋友应该都知道:真正干活的往往是那些 doXXX 开头的方法。这里也不例外,doGetBean()方法源码内容如下。

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return doGetBean(name, requiredType, null, false);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return doGetBean(name, null, args, false);
    }

    public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {
        return doGetBean(name, requiredType, args, false);
    }

    protected <T> T doGetBean(String name, Class<T> requiredType, Object[] args, boolean typeCheckOnly) throws BeansException {
        // § 2.1
        String beanName = transformedBeanName(name);
        Object beanInstance;

        // § 2.2
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            // § 2.3
            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        } else {
            // § 2.4
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory abf) {
                    return abf.doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
                } else if (args != null) {
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                } else if (requiredType != null) {
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                } else {
                    return (T) parentBeanFactory.getBean(nameToLookup);
                }
            }

            // § 2.5
            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }

            try {
                RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

                // § 2.6
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        registerDependentBean(dep, beanName);
                        try {
                            getBean(dep);
                        } catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                        }
                    }
                }

                // § 2.7
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        } catch (BeansException ex) {
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
            } catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }
        
        // § 2.8
        return adaptBeanInstance(name, beanInstance, requiredType);
    }
}
复制代码

代码很多,笔者已经在核心内容上打了标签 ( § 2.1 - § 2.8 ),下面就以这些标签作为独立的小节,逐一分析这些核心内容。

§ 2.1 转换 beanName

transformedBeanName() 方法会对传进来的 beanName 进行转换。如果传进来的 beanName 以 & 为前缀,那么这里会移除该前缀;如果传进来的 beanName 是某一个 Bean 的 aliasName,那么找到该 aliasName 真正所指向的 beanName。

一般情况下,Spring 结合 BeanDefinition 实例中的 beanClass 属性与反射机制来实例化 Bean。但某些情况下,实例化 Bean 的过程比较复杂,直接通过反射构建出来的实例没有太多意义。Spring 为此提供了一个可以灵活配置实例化 Bean 的方案,这一方案隐藏了实例化复杂 Bean 的细节,它就是大名鼎鼎的FactoryBean接口。getObject() 方法用于返回当前 FactoryBean 所创建的复杂 Bean 的实例。

public interface FactoryBean<T> {
    T getObject() throws Exception;
    Class<?> getObjectType();
    default boolean isSingleton() { return true; }
}
复制代码

Spring 自身针对 FactoryBean 接口就提供了多达 50+ 种实现类,咱们拿Jackson2ObjectMapperFactoryBean这个实现类来展开讲讲 FactoryBean 的应用场景。ObjectMapper是 Jackson 暴露给开发人员使用的核心序列化 API,在使用 ObjectMapper 之前,往往需要一些配置,毕竟一个裸的 ObjectMapper 实例很可能会有一些坑,更何况 Spring 对定制化配置 ObjectMapper 的诉求更为强烈,因此我们可以认为 ObjectMapper 这个 Bean 的实例化是复杂的。大家可以自行阅读 Jackson2ObjectMapperFactoryBean 类的源码,还是蛮清晰的。

§ 2.2 尝试从多级缓存中加载 Bean 实例

getSingleton(beanName) 方法会尝试从多级缓存中加载 Bean。缓存共计三级,分别是一级缓存singletonObjects、二级缓存earlySingletonObjects和三级缓存singletonFactories

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    // First cache.
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    // Second cache.
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
    // Third cache.
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    // Names of beans that are currently in creation.
    private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    public Object getSingleton(String beanName) {
        return getSingleton(beanName, true);
    }

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                synchronized (this.singletonObjects) {
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {
                                singletonObject = singletonFactory.getObject();
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }
        return singletonObject;
    }
}
复制代码

上述源码涉及三种 Map 类型的多级缓存,的确有些让人崩溃 (后面会解答),但总体逻辑还是清晰的。

  1. 首先从一级缓存 singletonObjects 中获取 Bean 实例,如果获取到了,则直接返回。
  2. 如果从一级缓存中未获取到且当前 Bean 正处于加载流程中,然后从二级缓存 earlySingletonObjects 里面获取,如果获取到了,则直接返回。
  3. 如果从二级缓存中还是没有获取到的话,那么从三级缓存 singletonFactory 里获取与 beanName 匹配的 ObjectFactory,接着调用 ObjectFactory 的getObject()方法来获取提前暴露的 Bean 实例 ( 如果需要为其生成代理,那此时还会为原始 Bean 实例生成代理类;此外,此时的 Bean 实例是一种早期状态,仅仅是实例化 createBeanInstance() 了而已,还未开始执行属性填充 populateBean() 和初始化 initializeBean() 这俩流程 ) ,最后将这一提前暴露的 Bean 实例放到二级缓存中,同时删除三级缓存中的内容。

当一个 Bean 实例被塞进一级缓存中,这意味着该 Bean 已经完成了加载流程,即走完了实例化 createBeanInstance()、属性填充 populateBean() 和初始化 initializeBean() 流程,真正具备使用的条件了;此外,一级缓存也是确保单例 Bean 在 Spring IoC 容器中唯一性的关键,因此一级缓存中的内容是不会删除的。

§ 2.3 Bean 实例是否是最终想要的

不论 Bean 实例是直接从多级缓存中拿到的,还是直接创建的,并不一定就是我们想要的。因此,在拿到 Bean 实例之后,第一件事就是执行getObjectFromFactoryBean()方法。

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
        // String FACTORY_BEAN_PREFIX = "&"
        // name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)
        if (BeanFactoryUtils.isFactoryDereference(name)) {
            // name 是未经 transformedBeanName() 方法转换过的
            // 如果 name 以 & 为前缀,但 Bean 实例却又不是 FactoryBean 类型的,那只能抛出异常了
            if (!(beanInstance instanceof FactoryBean)) {
                throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
            }
            if (mbd != null) {
                mbd.isFactoryBean = true;
            }
            // name 以 & 为前缀,说明当前 FactoryBean 类型的 Bean 实例就是最终想要的,直接返回即可
            return beanInstance;
        }

        // name 不以 & 为前缀
        // 如果当前 Bean 实例不是 FactoryBean 类型的,则直接返回该 Bean 实例
        if (!(beanInstance instanceof FactoryBean<?> factoryBean)) {
            return beanInstance;
        }

        // 执行到这里,说明 name 不以 & 为前缀,但当前 Bean 实例是 FactoryBean 类型的
        // 进一步说明:FactoryBean#getObject() 返回的 Bean 实例才是最终想要的
        Object object = null;
        if (mbd != null) {
            mbd.isFactoryBean = true;
        }
        if (object == null) {
            if (mbd == null && containsBeanDefinition(beanName)) {
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            boolean synthetic = (mbd != null && mbd.isSynthetic());
            // 核心逻辑
            object = getObjectFromFactoryBean(factoryBean, beanName, !synthetic);
        }
        return object;
    }
}
复制代码

getObjectFromFactoryBean() 方法主要逻辑有:

  1. 如果 name 以 & 为前缀且 Bean 实例是 BeanFactory 类型的,那当前 Bean 实例就是最终想要的。
  2. 如果 name 不以 & 为前缀且 Bean 实例不是 BeanFactory 类型的,那当前 Bean 实例就是最终想要的。
  3. 如果 name 不以 & 为前缀但 Bean 实例是 BeanFactory 类型的,那当前 Bean 实例并不是最终想要的,故而委派 getObjectFromFactoryBean() 方法来匹配最终想要的 Bean 实例。

很遗憾,当继续跟进到 getObjectFromFactoryBean() 方法中后,并没有我们想要看到的内容,但潜意识觉得 doGetObjectFromFactoryBean() 方法就是答案了,果然没让我们失望!

public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {
    private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
        Object object;
        try {
            object = factory.getObject();
        } catch (FactoryBeanNotInitializedException ex) {
            throw new BeanCurrentlyInCreationException(beanName, ex.toString());
        } catch (Throwable ex) {
            throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
        }
        return object;
    }
}
复制代码

§ 2.4 尝试从 parentBeanFactory 中加载 Bean

既然从多级缓存中没有获取到 Bean 实例,那只能从头开始、完整地走一遍 Bean 加载流程了,但 Spring 好像还不死心,想要试图从parentBeanFactory拿到。如果 parentBeanFactory 存在,则递归调用 getBean() 方法。

§ 2.5 提前标识当前 Bean 加载流程已完结

当程序执行到这里,说明确实要从头开始、完整地走一遍 Bean 加载流程,markBeanAsCreated()方法用于提前标识当前 Bean 加载流程已完结,毕竟接下来肯定要真正触发 Bean 加载流程的。

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    // Map from bean name to merged RootBeanDefinition.
    private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);
    // Names of beans that have already been created at least once.
    private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));

    protected void markBeanAsCreated(String beanName) {
        if (!this.alreadyCreated.contains(beanName)) {
            synchronized (this.mergedBeanDefinitions) {
                this.alreadyCreated.add(beanName);
            }
        }
    }
}
复制代码

§ 2.6 优先加载由 @DependsOn 注解标识的依赖 Bean

如果对 Bean A 的加载需要确保另一个 Bean B 已经加载完毕,而且 Bean B 并不是 Bean A 中所持有的成员变量,那就可以使用 @DependsOn 注解来满足这一需求。

如果当前 BeanDefinition 的 dependsOn 属性值非空,那么就要优先加载 dependsOn 属性中指定的 Bean 了。首先,委派registerDependentBean()方法来双向记录依赖关系;然后递归调用 getBean() 方法。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    // Map between dependent bean names: bean name to Set of dependent bean names.
    private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

    // Map between depending bean names: bean name to Set of bean names for the bean's dependencies.
    private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

    public void registerDependentBean(String beanName, String dependentBeanName) {
        synchronized (this.dependentBeanMap) {
            Set<String> dependentBeans =
                    this.dependentBeanMap.computeIfAbsent(beanName, k -> new LinkedHashSet<>(8));
            if (!dependentBeans.add(dependentBeanName)) {
                return;
            }
        }

        synchronized (this.dependenciesForBeanMap) {
            Set<String> dependenciesForBean =
                    this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
            dependenciesForBean.add(beanName);
        }
    }
}
复制代码

§ 2.7 真正开始创建 Bean 实例

getSingleton(beanName, () -> createBean(beanName, mbd, args)) 真正拉开了 Bean 加载流程的序幕,但 属性填充 populateBean() 和 初始化 initializeBean() 这两块内容放在第三章节与第四章节中讲解。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

    // Cache of singleton objects: bean name to bean instance.
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    // Cache of early singleton objects: bean name to bean instance.
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

    // Cache of singleton factories: bean name to ObjectFactory.
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    // Names of beans that are currently in creation.
    private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    // getSingleton(beanName, () -> createBean(beanName, mbd, args))
    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        synchronized (this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                // 	this.singletonsCurrentlyInCreation.add(beanName)
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                try {
                    // createBean(beanName, mbd, args))
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                } catch (BeanCreationException ex) {
                    throw ex;
                } finally {
                    // 	this.singletonsCurrentlyInCreation.remove(beanName)
                    afterSingletonCreation(beanName);
                }

                if (newSingleton) {
                    //	this.singletonObjects.put(beanName, singletonObject);
                    //	this.singletonFactories.remove(beanName);
                    //	this.earlySingletonObjects.remove(beanName);
                    addSingleton(beanName, singletonObject);
                }
            }

            return singletonObject;
        }
    }
}
复制代码

从上述代码我们可以总结出创建 Bean 实例的核心外围逻辑。

  1. 首先,向 singletonsCurrentlyInCreation 成员变量中插入 beanName,标识该 Bean 正处于加载流程中。
  2. 其次,回调ObjectFactorygetObject()方法,getObject() 方法中的全部逻辑就是调用 createBean() 方法,createBean() 方法涵盖了完整的 Bean 加载流程。
  3. 再次,此时 Bean 实例不仅创建完毕,而且还完成了属性填充 populateBean() 和 初始化 initializeBean() 流程,真正具备使用的条件了,那么自然要从 singletonsCurrentlyInCreation 中删除该 beanName,标识该 Bean 加载流程走完了。
  4. 最后,将 Bean 实例追加到一级缓存 singletonObjects 中,同时删除二级缓存 earlySingletonObjects 和三级缓存 singletonFactories 中的内容。

接下来,终于要到 createBean() 方法中去探寻真理了。

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {
    /**
     * Central method of this class: creates a bean instance,
     * populates the bean instance, applies post-processors, etc.
     */
    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
        RootBeanDefinition mbdToUse = mbd;
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        } catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        try {
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            return beanInstance;
        } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
            throw ex;
        } catch (Throwable ex) {
            throw new BeanCreationException(
                    mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
        }
    }
}
复制代码

显然,从上述 createBean() 方法内容来看,doCreateBean()方法才有我们想要的真理!但在执行 doCreateBean() 方法前有两个知识点需要大家去关注。

  1. 如果当前 BeanDefinition 实例的 beanClass 属性值是字符串类型的,那么 resolveBeanClass() 方法会根据字符串类型的 beanClass 解析出一个 Class 实例,然后替换更新 beanClass 属性值。这其中涉及的关键技术是 Spring EL。
public static void main(String[] args) {
    ConfigurableApplicationContext applicationContext = SpringApplication.run(MumuApplication.class, args);
    AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
    StandardBeanExpressionResolver beanExpressionResolver =
            new StandardBeanExpressionResolver(Thread.currentThread().getContextClassLoader());
    Object restTemplateBuilderClazz =
            beanExpressionResolver.evaluate("#{restTemplateBuilder.class}",
                    new BeanExpressionContext((ConfigurableBeanFactory) autowireCapableBeanFactory, null));
    Object restTemplateBuilderBean =
            beanExpressionResolver.evaluate("#{restTemplateBuilder}",
                    new BeanExpressionContext((ConfigurableBeanFactory) autowireCapableBeanFactory, null));
}
复制代码
  1. 大家应该清楚 Spring AOP 是通过BeanPostProcessor将原生 Bean 实例替换为代理对象的。而 resolveBeforeInstantiation() 方法同样是利用 BeanPostProcessor 来生成代理,但这里代理生成的时机更为靠前,因为原生 Bean 实例都还没有生成呢。卧槽,这一点我还真不知道!
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {
    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        Object bean = null;
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
            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;
    }

    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
        for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
            Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
            if (result != null) {
                return result;
            }
        }
        return null;
    }
}
复制代码

从 resolveBeforeInstantiation() 方法最终跟踪到了AbstractAutoProxyCreator类中,它当然是一个 BeanPostProcessor 实现类,主要内容如下。

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
        implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
        Object cacheKey = getCacheKey(beanClass, beanName);

        if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
            if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }

        // Create proxy here if we have a custom TargetSource.
        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;
    }
}
复制代码

从 AbstractAutoProxyCreator 关于代理的生成策略来看:如果基于 beanClass 可以获取到一个 TargetSource 实例,那么就将创建一个代理类。但笔者一路 DEBUG 下去,也没发现有代理类是在这里创建的,因此这里不做过多展开了,真不太懂这玩意儿呢。

好了!这两个需要大家关注的知识点讲完了,接下来就要专心攻坚 doCreateBean() 这家伙了。

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {

    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {

        // Instantiate the bean.
        BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.markAsPostProcessed();
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException bce && beanName.equals(bce.getBeanName())) {
                throw bce;
            } else {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
            }
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                        StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                        "] in its raw version as part of a circular reference, but has eventually been " +
                                        "wrapped. This means that said other beans do not use the final version of the " +
                                        "bean. This is often the result of over-eager type matching - consider using " +
                                        "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        // Register bean as disposable.
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        } catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }
}
复制代码

为了加深印象,这里贴一张 doCreateBean() 方法的 UML 时序图,如下所示。

do_create_bean_uml_sequence.png

在上述 doCreateBean() 方法的源码中,我们终于看到了 createBeanInstance()populateBean()initializeBean() 的身影。刚刚说了,populateBean() 和 initializeBean() 这俩方法在后续章节分析,而笔者也不打算分析 createBeanInstance() 方法的内容,这个内容真是晦涩难懂啊,记住 “Bean 实例主要是通过反射机制来构建” 这一点就行了。

在 createBeanInstance() 方法执行完之后,紧接着执行applyMergedBeanDefinitionPostProcessors()方法,主要是遍历MergedBeanDefinitionPostProcessor并调用其postProcessMergedBeanDefinition()方法。MergedBeanDefinitionPostProcessor 的应用时机介于 实例化 createBeanInstance() 与 属性填充 populateBean() 之间,为后续 属性填充 populateBean() 和 初始化 initializeBean() 阶段提前缓存LifecycleMetadataInjectionMetadata。MergedBeanDefinitionPostProcessor 接口有三个重要的实现类,如下所示。

docreate_bean_mbdbpp_postprocess_mbd.png

  • 在 InitDestroyAnnotationBeanPostProcessor 中,其 postProcessMergedBeanDefinition() 方法负责将由 @PostConstruct、@PreDestroy 注解修饰的方法封装为 LifecycleMetadata 实例,然后将其缓存到该类的成员变量lifecycleMetadataCache中。

  • 在 CommonAnnotationBeanPostProcessor 中,其 postProcessMergedBeanDefinition() 方法负责将由 @Resource 注解修饰的变量或方法封装为 InjectionMetadata 实例,然后将其缓存到该类的成员变量injectionMetadataCache中。

  • 在 AutowiredAnnotationBeanPostProcessor 中,其 postProcessMergedBeanDefinition() 方法负责将由 @Autowired、@Value、@Inject 注解修饰的变量或方法封装为 InjectionMetadata 实例,然后将其缓存到该类的成员变量injectionMetadataCache中。

下面开始剖析 Spring 是如何解决循环依赖这一问题的!Spring Boot 自 2.6.0 版本开始默认不允许循环依赖,需要通过spring.main.allow-circular-references配置项手动开启该功能。

首先,要搞清楚啥是循环依赖。循环依赖就是循环引用,比如 Bean A 引用了 Bean B,而 Bean B 又引用了 Bean A,最终导致二者之间形成了一个引用环。如果引用关系是通过构造方法来搭建的,那么这种循环依赖是无解的,但如果引用关系是通过 setter 方法来搭建的,那么 Spring 是完全有能力破局的。循环依赖可以分为下图中的这两种类型,其他情形的循环依赖都是它们的变体而已。

ciclo_referencia.png

为了解决循环依赖问题,Spring 的策略是不等 Bean 加载流程全部完成,在实例化完成之后就将 Bean 实例提前暴露出来,它是如何暴露的呢?

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
        isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
    if (logger.isTraceEnabled()) {
        logger.trace("Eagerly caching bean '" + beanName +
                "' to allow for resolving potential circular references");
    }
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
复制代码

可以发现,提前暴露 Bean 实例是通过addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))这一行代码实现的。

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(singletonFactory, "Singleton factory must not be null");
    synchronized (this.singletonObjects) {
        if (!this.singletonObjects.containsKey(beanName)) {
            this.singletonFactories.put(beanName, singletonFactory);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }
}
复制代码

最终,addSingletonFactory()方法通过getEarlyBeanReference(beanName, mbd, bean)方法来将该 Bean 实例包装为一个ObjectFactory,然后丢到三级缓存 singletonFactories 中。

看到这里,相信大家肯定会有一个疑惑:明明 Bean 实例已经生成了,它就在那里,为啥还要通过 getEarlyBeanReference(beanName, mbd, bean) 方法来获取 Bean 实例呢,这不是“脱裤子放屁,多此一举”吗?

为了解答这一疑惑,我们先来看一下 getEarlyBeanReference(beanName, mbd, bean) 方法都干了啥吧。

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
            exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
        }
    }
    return exposedObject;
}
复制代码

继续跟踪到AbstractAutoProxyCreator中的 getEarlyBeanReference() 方法中。

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
        implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        this.earlyProxyReferences.put(cacheKey, bean);
        return wrapIfNecessary(bean, beanName, cacheKey);
    }
}
复制代码

看到wrapIfNecessary()方法就应该明白了!wrapIfNecessary() 方法负责探测是否需要为某一 Bean 创建代理,如果需要就将为其创建代理。但代理类的创建多发生于初始化阶段,这里为啥将这一动作提前了呢?当然,如果 getEarlyBeanReference(beanName, mbd, bean) 确实为某一 Bean 生成了代理类,后续初始化阶段也不会重新生成代理类,因为在 AbstractAutoProxyCreator 中有一个成员变量earlyProxyReferences可以标识这一状态。

现在,我们只需要搞清楚一个问题就行了,那就是 getEarlyBeanReference(beanName, mbd, bean) 方法为什么会如此着急地创建代理?细细想来,这么做绝对是正确的。假设 Bean A 与 Bean B 构成循环依赖关系,而且 Bean A 是需要 Spring AOP 为其生成代理的,也就是说最终驻留在 IoC 容器中的 Bean A 是一个代理。

  1. 尝试从多级缓存中加载 Bean A,此时肯定是加载不到的,必须要完整走一遍 Bean 加载流程了。
  2. createBeanInstance() 方法为 Bean A 生成原生的 Bean 实例。
  3. 将 Bean A 的实例提前暴露到三级缓存 singletonObjects 中,此时由于需要为 Bean A 生成代理,那么最终躺在三级缓存 singletonObjects 中的是其代理。
  4. populateBean() 方法为 Bean A 进行属性填充,这时发现需要为 Bean A 注入 Bean B。
  5. 尝试从多级缓存中加载 Bean B,此时肯定是加载不到的,必须要完整走一遍 Bean 加载流程了。
  6. createBeanInstance() 方法为 Bean B 生成 Bean 实例。
  7. 将 Bean B 的实例提前暴露到三级缓存 singletonObjects 中。
  8. populateBean() 方法为 Bean B 进行属性填充,这时发现需要为 Bean B 注入 Bean A,自然会触发对 Bean A 的加载流程。
  9. 这个时候已经可以从多级缓存中加载到 Bean A 了,因为它此刻正躺在三级缓存 singletonObjects 中呢。
  10. populateBean() 方法会触发 getBean(Bean A) 的加载流程,既然直接从多级缓存中拿到了 Bean A,接下来,自然是继续为 Bean B 注入 Bean A 了。

想象一下,如果 getEarlyBeanReference(beanName, mbd, bean) 方法没有将创建代理的动作提前,那么此时此刻注入到 Bean B 中的 Bean A 只是其原生的实例,而不再是代理!

最后,再看一个关于多级缓存与循环依赖的知识点,内容如下所示,依然是 doCreateBean() 方法中的内容。

Object exposedObject = bean;
try {
    populateBean(beanName, mbd, instanceWrapper);
    exposedObject = initializeBean(beanName, exposedObject, mbd);
} catch (Throwable ex) {
    throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
}

if (earlySingletonExposure) {
    Object earlySingletonReference = getSingleton(beanName, false);
    if (earlySingletonReference != null) {
        if (exposedObject == bean) {
            exposedObject = earlySingletonReference;
        } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
            String[] dependentBeans = getDependentBeans(beanName);
            Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
            for (String dependentBean : dependentBeans) {
                if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                    actualDependentBeans.add(dependentBean);
                }
            }
            if (!actualDependentBeans.isEmpty()) {
                throw new BeanCurrentlyInCreationException(beanName,
                        "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
            }
        }
    }
}
复制代码

笔者在看完上述内容后,也是思考了许久才搞明白。主要不理解actualDependentBeans非空的话,为啥就需要抛出异常。后来结合那一长坨异常信息才顿悟了,有点无语,哈哈。首先,通过 getSingleton(beanName, false)方法从多级缓存中加载 Bean,注意传入的 allowEarlyReference 参数值为 false,也就是说只会尝试从一级缓存 singletonObjects 和 二级缓存 earlySingletonObjects 中加载 Bean 了。如果 getSingleton(beanName, false) 方法加载到的 Bean 是来自于二级缓存 earlySingletonObjects 的,那说明什么问题?记住:一旦某一 Bean 的早期实例从三级缓存 singletonFactories 转移到了二级缓存 earlySingletonObjects 中,那么该 Bean 一定是与另一个 Bean 构成了循环依赖,而且转移的时机就是另一个与其循环依赖的 Bean 将其作为依赖注入进去了;换句话说,在循环依赖场景下,二级缓存 earlySingletonObjects 是用来标识某一早期 Bean 实例是否被别人拿去注入了。

有了这些知识的铺垫,理解上述内容就容易很多了。如果 getSingleton(beanName, false) 方法返回的 earlySingletonReference 非空且 earlySingletonReference 与 exposedObject 不一致,那说明 initializeBean() 方法生成了代理 Bean,而此时 earlySingletonReference 这个早前 Bean 实例已经被其他 Bean 使用 (注入) 了,这时 actualDependentBeans 肯定是非空的,当然要抛出异常了!

§ 2.8 转换 Bean 实例为特定类型

Bean 的加载流程已经接近尾声了,还有最后一个步骤,就是对 Bean 进行类型转换。大多数情况下,adaptBeanInstance() 方法中 requiredType 这一参数值是空的,也就是毛都不做;但如果 requiredType 非空,那就需要将 Bean 实例转换为特定的类型。

public abstract class AbstractBeanFactory {
    public <T> T adaptBeanInstance(String name, Object bean, Class<?> requiredType) {
        if (requiredType != null && !requiredType.isInstance(bean)) {
            try {
                Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
                if (convertedBean == null) {
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
                return (T) convertedBean;
            } catch (TypeMismatchException ex) {
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        }

        return (T) bean;
    }
}
复制代码

实例化的逻辑难就难在循环依赖这一块,除此之外也没啥别的干货了,Bean 加载流程中的干货基本都是在属性填充与初始化这俩环节。

3 属性填充

populate_bean_uml_sequence.png

关于属性填充或者属性注入的概念,大家或多或少都了解一些,下面就一起来看看它的全部逻辑吧。

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {
    /**
     * Populate the bean instance in the given BeanWrapper with the property values
     * from the bean definition.
     */
    protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
        // § 3.1
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
                if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    return;
                }
            }
        }


        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
        int resolvedAutowireMode = mbd.getResolvedAutowireMode();
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
            // Add property values based on autowire by name if applicable.
            if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
                // § 3.2
                autowireByName(beanName, mbd, bw, newPvs);
            }
            // Add property values based on autowire by type if applicable.
            if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
                // § 3.3
                autowireByType(beanName, mbd, bw, newPvs);
            }
            pvs = newPvs;
        }

        // § 3.4
        if (hasInstantiationAwareBeanPostProcessors()) {
            if (pvs == null) {
                pvs = mbd.getPropertyValues();
            }
            for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
                PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                if (pvsToUse == null) {
                    return;
                }
                pvs = pvsToUse;
            }
        }

        // § 3.5
        if (pvs != null) {
            applyPropertyValues(beanName, mbd, bw, pvs);
        }
    }
}
复制代码

§ 3.1 postProcessAfterInstantiation()

Spring 针对 Bean 实例化之后、属性填充之前的这一阶段,通过InstantiationAwareBeanPostProcessorpostProcessAfterInstantiation()方法提供了一个拓展点,postProcessAfterInstantiation() 方法返回 false,那么后续将不再进行属性填充操作。目前,笔者还没有发现哪里使用到了这一拓展点,大家了解即可。

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
    /**
     * Perform operations after the bean has been instantiated, via a constructor or factory method,
     * but before Spring property population (from explicit properties or autowiring) occurs.
     * <p>The default implementation returns {@code true}.
     * @param bean the bean instance created, with properties not having been set yet
     * @param beanName the name of the bean
     * @return {@code true} if properties should be set on the bean; {@code false}
     * if property population should be skipped. Normal implementations should return {@code true}.
     */
    default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }
}
复制代码

§ 3.2 autowireByName()

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {
    protected void autowireByName(
            String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
        String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
        for (String propertyName : propertyNames) {
            // 	public boolean containsBean(String name) {
            //		String beanName = transformedBeanName(name);
            //		if (containsSingleton(beanName) || containsBeanDefinition(beanName)) {
            //			return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));
            //		}
            //		return false
            //	}
            //  -------------------------------------------------------------------------
            // 	public boolean containsSingleton(String beanName) {
            //		return this.singletonObjects.containsKey(beanName);
            //	}
            //  -------------------------------------------------------------------------
            // 	public boolean containsBeanDefinition(String beanName) {
            //		Assert.notNull(beanName, "Bean name must not be null");
            //		return this.beanDefinitionMap.containsKey(beanName);
            //	}
            if (containsBean(propertyName)) {
                Object bean = getBean(propertyName);
                pvs.add(propertyName, bean);
                registerDependentBean(propertyName, beanName);
            }
        }
    }

    protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
        Set<String> result = new TreeSet<>();
        PropertyValues pvs = mbd.getPropertyValues();
        PropertyDescriptor[] pds = bw.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
            if (pd.getWriteMethod() != null && !pvs.contains(pd.getName()) &&
                    !BeanUtils.isSimpleProperty(pd.getPropertyType())) {
                result.add(pd.getName());
            }
        }
        return StringUtils.toStringArray(result);
    }
}
复制代码

每个 RootBeanDefinition 实例持有一MutablePropertyValues类型的成员变量,该成员变量持有若干个PropertyValue实例,而一个 PropertyValue 实例则代表着一对 key/value 键值对儿。autowireByName()方法的核心逻辑就是向当前 RootBeanDefinition 实例所持有的 MutablePropertyValues 变量内插入一个或多个 PropertyValue 实例,此时 PropertyValue 实例的 key 是当前 Bean 实例中某一成员变量名,value 则是 IoC 容器中一个以 key 为 beanName 的 Bean 实例,如果该 Bean 尚未加载,那么此时会进行 Bean 加载。

一个 Bean 实例中会有多个成员变量,那么究竟哪些成员变量才有资格被封装成一个 PropertyValue 实例、最终进入到 MutablePropertyValues 中呢?

  1. 首先,在一级缓存 singletonObjects 与 beanDefinitionMap 二者中至少有一个能匹配到该 beanName。
  2. 其次,该成员变量必须要有相应的 setter 方法;由 @Autowired 或 @Resource 注解标注的成员变量一般是过不了这一关的,因为咱们平时很少为它们编写 setter 方法。
  3. 再次,该成员变量名称在当前 RootBeanDefinition 实例所持有的成员变量 MutablePropertyValues 中必须是不存在。
  4. 最后,该成员变量的类型不能是一种Simple Property,具体参考下图。

simple_property_in_populating_bean.png

§ 3.3 autowireByType()

autowireByType() 方法与 autowireByName() 方法的核心逻辑是一致的,首先将当前 Bean 实例中符合条件的成员变量封装为一个 PropertyValue 实例,然后把这些 PropertyValue 实例塞进相应 RootBeanDefinition 实例的成员变量 MutablePropertyValues 中去。但相较于 autowireByName() 方法,autowireByType() 方法内容却复杂得多,这是为什么呢?在上一小节中曾提到:PropertyValue 实例所持有的 value 是一个已完成加载流程的 Bean 实例。在 byName 场景下,这么说是没问题的,因为在 IoC 容器中 beanName 与 Bean 实例是一一对应的;但在 byType 场景下可就不一定了,因为在 IoC 容器中 beanType 与 Bean 实例可以是一对多的关系!

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
    protected void autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
        TypeConverter converter = getCustomTypeConverter();
        if (converter == null) {
            converter = bw;
        }
        Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
        String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
        for (String propertyName : propertyNames) {
            try {
                PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
                if (Object.class != pd.getPropertyType()) {
                    MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
                    boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
                    DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
                    // 核心逻辑
                    Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
                    if (autowiredArgument != null) {
                        // 最终目的
                        pvs.add(propertyName, autowiredArgument);
                    }
                    for (String autowiredBeanName : autowiredBeanNames) {
                        registerDependentBean(autowiredBeanName, beanName);
                    }
                    autowiredBeanNames.clear();
                }
            } catch (BeansException ex) {
                throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
            }
        }
    }
}
复制代码

大家应该可以很自然地想到resolveDependency()方法所解析出的结果可能是一个已完成加载流程的 Bean 实例,也可能是一个 ArrayCollection或者Map类型、包含多个同一 beanType 且已完成加载流程的 Bean 实例。为什么这么肯定 Bean 实例一定是已完成加载流程的呢?因为 resolveDependency() 方法内部最终也是委派 AbstractBeanFactory 的 getBean(beanName) 方法来拿到想要的单例 Bean。

resolveDependency()方法绝对是重中之重,但源码太长了,一层套一层的,这里仅贴出它所极度依赖的findAutowireCandidates()方法吧。

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    /**
     * Find bean instances that match the required type.
     * Called during autowiring for the specified bean.
     */
    protected Map<String, Object> findAutowireCandidates(@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
        // 核心逻辑
        String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this, requiredType, true, descriptor.isEager());
        Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);
        for (String candidate : candidateNames) {
            if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
                // 核心逻辑
                addCandidateEntry(result, candidate, descriptor, requiredType);
            }
        }
        return result;
    }

    private void addCandidateEntry(Map<String, Object> candidates, String candidateName,
                                   DependencyDescriptor descriptor, Class<?> requiredType) {
        if (descriptor instanceof MultiElementDescriptor) {
            Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
            if (!(beanInstance instanceof NullBean)) {
                candidates.put(candidateName, beanInstance);
            }
        } else if (containsSingleton(candidateName) || (descriptor instanceof StreamDependencyDescriptor streamDescriptor && streamDescriptor.isOrdered())) {
            Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
            candidates.put(candidateName, (beanInstance instanceof NullBean ? null : beanInstance));
        } else {
            candidates.put(candidateName, getType(candidateName));
        }
    }
}

public class DependencyDescriptor extends InjectionPoint implements Serializable {
    public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
            throws BeansException {
        return beanFactory.getBean(beanName);
    }
}
复制代码

§ 3.4 postProcessProperties()

postProcessProperties()方法由InstantiationAwareBeanPostProcessor接口声明,是一种面向注解的依赖注入拓展点。Spring 为其提供了两个极其重要的实现类,如下图所示。

populating_bean_bpp_postprocess_properties.png

3.4.1 CommonAnnotationBeanPostProcessor

CommonAnnotationBeanPostProcessor中,postProcessProperties() 方法负责为 Bean 实例内由@Resource注解标识的成员变量注入依赖。

public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
        implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
        try {
            metadata.inject(bean, beanName, pvs);
        } catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
        }
        return pvs;
    }
}
复制代码
public class InjectionMetadata {
    public void inject(Object target, String beanName,PropertyValues pvs) throws Throwable {
        Collection<InjectedElement> checkedElements = this.checkedElements;
        Collection<InjectedElement> elementsToIterate =
                (checkedElements != null ? checkedElements : this.injectedElements);
        if (!elementsToIterate.isEmpty()) {
            for (InjectedElement element : elementsToIterate) {
                element.inject(target, beanName, pvs);
            }
        }
    }

    protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
            throws Throwable {
        if (this.isField) {
            Field field = (Field) this.member;
            ReflectionUtils.makeAccessible(field);
            field.set(target, getResourceToInject(target, requestingBeanName));
        } else {
            try {
                Method method = (Method) this.member;
                ReflectionUtils.makeAccessible(method);
                method.invoke(target, getResourceToInject(target, requestingBeanName));
            } catch (InvocationTargetException ex) {
                throw ex.getTargetException();
            }
        }
    }
}
复制代码

InjectionMetadata源码内容可以明显看出最终是通过反射机制来实现依赖注入的!

3.4.2 AutowiredAnnotationBeanPostProcessor

AutowiredAnnotationBeanPostProcessor中,postProcessProperties() 方法负责为 Bean 实例内由@Autowired@Value@Inject注解标识的成员变量注入依赖。

public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
        MergedBeanDefinitionPostProcessor, BeanRegistrationAotProcessor, PriorityOrdered, BeanFactoryAware {
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
        try {
            metadata.inject(bean, beanName, pvs);
        } catch (BeanCreationException ex) {
            throw ex;
        } catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
        }
        return pvs;
    }
}
复制代码

从上面源码内容来看,CommonAnnotationBeanPostProcessor 与 AutowiredAnnotationBeanPostProcessor 最终都是以 InjectionMetadata 进行依赖注入,但各自findAutowiringMetadata()方法中的逻辑是不一样的,因为面向的是不同类型的注解。此外,有必要提一下@Value注解的解析逻辑,解析入口位于ConfigurableBeanFactory接口中的resolveEmbeddedValue()方法,其内部会委派StringValueResolver去解析,PlaceholderResolvingStringValueResolver是 StringValueResolver 接口一个比较重要的实现类,@Value注解的解析逻辑最终就在该实现类中!

§ 3.5 applyPropertyValues()

程序运行到这里,当前 Bean 实例内由@Resource@Autowired@Value@Inject注解标识的成员变量已经全部完成了依赖注入,但当前 RootBeanDefinition 实例内 MutablePropertyValues 类型的成员变量中还有若干 PropertyValue 实例没有被当成依赖而注入到当前 Bean 实例中去,这些 PropertyValue 实例主要是由autowireByName()autowireByType()方法塞进来的,当然也可以由开发人员自定义的BeanFactoryPostProcessor实现类来置入。

最终也是通过反射机制为当前 Bean 实例实现依赖注入的,如下图所示。

apply_property_values_core.png

4 初始化

initialize_bean_uml_sequence.png

谢天谢地!我们终于来到了较为轻松的初始化阶段。对@PostConstructInitializingBeanCustom Init Method这三种初始化方法的调用绝不仅仅是初始化阶段的全部,事实上还有更为重要的知识点值得我们去关注。

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
    /**
     * Initialize the given bean instance, applying factory callbacks
     * as well as init methods and bean post processors.
     */
    protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
        // § 4.1
        invokeAwareMethods(beanName, bean);

        // § 4.2
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        // § 4.3
        try {
            invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
        }

        // § 4.4
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }
}
复制代码

从上述源码内容来看,针对 Bean 的初始化逻辑由四部分组成。下面对这四部分内容进行逐一击破!

§ 4.1 invokeAwareMethods()

invokeAwareMethods() 方法简单得已经没啥好说的了,直接贴代码就完事了。

private void invokeAwareMethods(String beanName, Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware beanNameAware) {
            beanNameAware.setBeanName(beanName);
        }
        if (bean instanceof BeanClassLoaderAware beanClassLoaderAware) {
            ClassLoader bcl = getBeanClassLoader();
            if (bcl != null) {
                beanClassLoaderAware.setBeanClassLoader(bcl);
            }
        }
        if (bean instanceof BeanFactoryAware beanFactoryAware) {
            beanFactoryAware.setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}
复制代码

§ 4.2 applyBeanPostProcessorsBeforeInitialization()

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessBeforeInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}
复制代码

从上述源码内容来看,applyBeanPostProcessorsBeforeInitialization()方法主要就是遍历 BeanPostProcessor 并调用其 postProcessBeforeInitialization() 方法。 那么究竟有哪些 BeanPostProcessor 实现类恰好实现了 postProcessBeforeInitialization() 方法呢? 比较重要的有三个,如下所示。

initializing_bean_bpp_postprocess_before_initialization.png

下面以两个小节分别对 ConfigurationPropertiesBindingPostProcessor 与 InitDestroyAnnotationBeanPostProcessor 进行剖析。

4.2.1 ConfigurationPropertiesBindingPostProcessor

大家也许知道,一个外部配置源与一个PropertySource是一一对应的,一个 PropertySource 实例中可以有多个配置项;但在 Spring 的地盘,还是要入乡随俗,这些 PropertySource 均会被追加到Environment中 ! 而本小节的主角ConfigurationPropertiesBindingPostProcessor可以将外部配置源中的配置项绑定到由@ConfigurationProperties注解标注的 Bean 实例中,当然真正实现配置绑定的是 Spring Boot 自己提供的Binder API

Binder API 中有四个核心类。Binder会进行真正地绑定操作,其提供多个绑定动作方法,如:bind()、bindObject() 和 bindOrCreate() 等方法;Bindable代表可绑定的目标,其支持泛型;BindResult代表绑定过后的结果,有点类似OptionalBindHandler用于在绑定过程中插入一些额外的逻辑,它提供了五个方法:onStart()、onSuccess()、onCreate()、onFailure() 和 onFinish()。

下面通过一段代码来演示一下 Binder API 的魅力。

@Data
public class PersonProperties {
    private String firstName;
    private int age;
}

@SpringBootApplication
public class MumuApplication {
    public static void main(String[] args) {
        /*
         *        application.properties
         * =====================================
         * external-config.person.first-name=duxiaotou
         * external-config.person.age=18
         */
        ConfigurableApplicationContext wac = SpringApplication.run(MumuApplication.class, args);
        ConfigurableEnvironment environment = wac.getEnvironment();
        Binder binder = Binder.get(environment);
        Bindable<PersonProperties> bindableTarget = Bindable.of(PersonProperties.class);
        BindResult<PersonProperties> bindResult = binder.bind(ConfigurationPropertyName.of("external-config.person"), bindableTarget);
        PersonProperties personProperties = bindResult.get();
    }
}
复制代码

这里想问大家一个问题:如果将 application.properties 配置文件中的配置项修改为 external-config.person.FIRSTNAMEexternal-config.person.first_nameexternal-config.person.firstName ,那么还能正常绑定吗?答案是肯定的,这正是由 Spring Boot 提出的relaxed binding概念!

下面咱们再来看一看 ConfigurationPropertiesBindingPostProcessor 中 postProcessBeforeInitialization() 方法的内容。

public class ConfigurationPropertiesBindingPostProcessor 
        implements BeanPostProcessor, PriorityOrdered, ApplicationContextAware, InitializingBean {
    
    private ApplicationContext applicationContext;
    
    private ConfigurationPropertiesBinder binder;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void afterPropertiesSet() {
        this.binder = ConfigurationPropertiesBinder.get(this.applicationContext);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));
        return bean;
    }

    private void bind(ConfigurationPropertiesBean bean) {
        if (bean == null || hasBoundValueObject(bean.getName())) {
            return;
        }
        try {
            this.binder.bind(bean);
        } catch (Exception ex) {
            throw new ConfigurationPropertiesBindException(bean, ex);
        }
    }
}
复制代码

继续跟进到ConfigurationPropertiesBinder中一探究竟。

public class ConfigurationPropertiesBinder {
    
    private final ApplicationContext applicationContext;

    private final PropertySources propertySources;

    private volatile Binder binder;

    public ConfigurationPropertiesBinder(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        this.propertySources = new PropertySourcesDeducer(applicationContext).getPropertySources();
        this.configurationPropertiesValidator = getConfigurationPropertiesValidator(applicationContext);
        this.jsr303Present = ConfigurationPropertiesJsr303Validator.isJsr303Present(applicationContext);
    }

    public BindResult<?> bind(ConfigurationPropertiesBean propertiesBean) {
        Bindable<?> target = propertiesBean.asBindTarget();
        ConfigurationProperties annotation = propertiesBean.getAnnotation();
        BindHandler bindHandler = getBindHandler(target, annotation);
        return getBinder().bind(annotation.prefix(), target, bindHandler);
    }
}
复制代码

上述源码内容明确地告诉我们:ConfigurationPropertiesBinder 正是通过 Binder API 来实现配置项绑定的。

熟悉 Environment 的读者肯定知道,Environment 中包含多个不同名称的 PropertySource,比如:command line argsservlet config init paramsservlet context init paramssystem propertiessystem environmentannotation-{profile}.properties 等。但这些 PropertySource 是不具备relaxed binding能力的,那么 Sping Boot 又是如何为这一众 PropertySource 插上relaxed binding翅膀的呢?原来,Spring Boot 会提早插入一个名为configurationProperties的 PropertySourc,而且这个 PropertySource 位于 MutablePropertySources 最顶端。如下所示。

public final class ConfigurationPropertySources {
    
    private static final String ATTACHED_PROPERTY_SOURCE_NAME = "configurationProperties";
    
    public static void attach(Environment environment) {
        MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();
        PropertySource<?> attached =
                new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME, new SpringConfigurationPropertySources(sources));
        sources.addFirst(attached);
    }
}
复制代码

上述 attach() 方法内容表明,这些不具备 relaxed binding 能力的 PropertySource 全部被丢进了SpringConfigurationPropertySources中,它的主要内容如下。

public class SpringConfigurationPropertySources implements Iterable<ConfigurationPropertySource> {

    private final Iterable<PropertySource<?>> sources;

    private final Map<PropertySource<?>, ConfigurationPropertySource> cache =
            new ConcurrentReferenceHashMap<>(16, ConcurrentReferenceHashMap.ReferenceType.SOFT);

    public SpringConfigurationPropertySources(Iterable<PropertySource<?>> sources) {
        this.sources = sources;
    }

    @Override
    public Iterator<ConfigurationPropertySource> iterator() {
        return new SourcesIterator(this.sources.iterator(), this::adapt);
    }

    private ConfigurationPropertySource adapt(PropertySource<?> source) {
        ConfigurationPropertySource result = this.cache.get(source);
        if (result != null) {
            return result;
        }
        result = SpringConfigurationPropertySource.from(source);
        if (source instanceof OriginLookup) {
            result = result.withPrefix(((OriginLookup<?>) source).getPrefix());
        }
        this.cache.put(source, result);
        return result;
    }
}

public class SpringConfigurationPropertySource implements ConfigurationPropertySource {
    public static SpringConfigurationPropertySource from(PropertySource<?> source) {
        Assert.notNull(source, "Source must not be null");
        PropertyMapper[] mappers = getPropertyMappers(source);
        if (isFullEnumerable(source)) {
            return new SpringIterableConfigurationPropertySource((EnumerablePropertySource<?>) source, mappers);
        }
        return new SpringConfigurationPropertySource(source, mappers);
    }
}
复制代码

从 SpringConfigurationPropertySources 源码内容来看,在对塞进来的 PropertySource 进行遍历的时候,会涉及适配操作。无非就是将一个个不具备 relaxed binding 能力的 PropertySource 适配成 SpringConfigurationPropertySource或者SpringIterableConfigurationPropertySource。SpringIterableConfigurationPropertySource 继承自 SpringConfigurationPropertySource,这哥俩恰恰具备完整的 relaxed binding 能力!最后一个问题,谁会来调用 SpringConfigurationPropertySources 的 iterator() 方法呢?当然是 Binder 在进行配置项绑定的时候,会通过其findProperty方法触发遍历动作。

public class Binder {
    private <T> ConfigurationProperty findProperty(ConfigurationPropertyName name,
                                                   Bindable<T> target,
                                                   Binder.Context context) {
        if (name.isEmpty() || target.hasBindRestriction(Bindable.BindRestriction.NO_DIRECT_PROPERTY)) {
            return null;
        }
        // context.getSources()
        //  ==> SpringConfigurationPropertySources#iterator()
        //   ==> SpringConfigurationPropertySources#adapt
        for (ConfigurationPropertySource source : context.getSources()) {
            ConfigurationProperty property = source.getConfigurationProperty(name);
            if (property != null) {
                return property;
            }
        }
        return null;
    }
}
复制代码
4.2.2 InitDestroyAnnotationBeanPostProcessor

InitDestroyAnnotationBeanPostProcessor主要用于调用当前 Bean 实例中由@PostConstruct以及@PreDestroy注解修饰的方法。 在其 postProcessBeforeInitialization() 方法内,首先通过 findLifecycleMetadata() 方法找到LifecycleMetadata实例,LifecycleMetadata 实例封装了@PostConstruct以及@PreDestroy注解修饰的方法,同时这个 LifecycleMetadata 实例会被缓存到Map<Class<?>, LifecycleMetadata>类型的成员变量 lifecycleMetadataCache 中,然后调用该 LifecycleMetadata 实例的 invokeInitMethods() 方法。 详细内容如下所示。

public class InitDestroyAnnotationBeanPostProcessor implements MergedBeanDefinitionPostProcessor, DestructionAwareBeanPostProcessor {
    /**
     * jakarta.annotation.PostConstruct
     */
    private Class<? extends Annotation> initAnnotationType;
    /**
     * jakarta.annotation.PreDestroy
     */
    private Class<? extends Annotation> destroyAnnotationType;

    private final transient Map<Class<?>, LifecycleMetadata> lifecycleMetadataCache = new ConcurrentHashMap<>(256);

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
        try {
            metadata.invokeInitMethods(bean, beanName);
        } catch (InvocationTargetException ex) {
            throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
        } catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
        }
        return bean;
    }

    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
        try {
            metadata.invokeDestroyMethods(bean, beanName);
        } catch (InvocationTargetException ex) {
            logger.warn("Destroy method on bean with name '" + beanName + "' threw an exception" + ": " + ex.getTargetException());
        } catch (Throwable ex) {
            logger.warn("Failed to invoke destroy method on bean with name '" + beanName + "'", ex);
        }
    }

    private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
        if (this.lifecycleMetadataCache == null) {
            return buildLifecycleMetadata(clazz);
        }
        LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
        if (metadata == null) {
            synchronized (this.lifecycleMetadataCache) {
                metadata = this.lifecycleMetadataCache.get(clazz);
                if (metadata == null) {
                    metadata = buildLifecycleMetadata(clazz);
                    this.lifecycleMetadataCache.put(clazz, metadata);
                }
                return metadata;
            }
        }
        return metadata;
    }

    private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
        if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
            return this.emptyLifecycleMetadata;
        }

        List<LifecycleElement> initMethods = new ArrayList<>();
        List<LifecycleElement> destroyMethods = new ArrayList<>();
        Class<?> targetClass = clazz;

        do {
            final List<LifecycleElement> currInitMethods = new ArrayList<>();
            final List<LifecycleElement> currDestroyMethods = new ArrayList<>();

            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
                    LifecycleElement element = new LifecycleElement(method);
                    currInitMethods.add(element);
                    if (logger.isTraceEnabled()) {
                        logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
                    }
                }
                if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
                    currDestroyMethods.add(new LifecycleElement(method));
                    if (logger.isTraceEnabled()) {
                        logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
                    }
                }
            });

            initMethods.addAll(0, currInitMethods);
            destroyMethods.addAll(currDestroyMethods);
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);

        return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
                new LifecycleMetadata(clazz, initMethods, destroyMethods));
    }
}
复制代码

§ 4.3 invokeInitMethods()

invokeInitMethods()El método también es muy simple, primero llama InitializingBeanal método afterPropertiesSet() y luego llama al Método de inicio personalizado (es decir, el método especificado por el valor del atributo initMethod en la anotación @Bean).

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null)) {
        ((InitializingBean) bean).afterPropertiesSet();
    }

    if (mbd != null && bean.getClass() != NullBean.class) {
        String[] initMethodNames = mbd.getInitMethodNames();
        if (initMethodNames != null) {
            for (String initMethodName : initMethodNames) {
                if (StringUtils.hasLength(initMethodName) &&
                        !(isInitializingBean && "afterPropertiesSet".equals(initMethodName))) {
                    invokeCustomInitMethod(beanName, bean, mbd, initMethodName);
                }
            }
        }
    }
}
复制代码

Combinando las dos secciones de § 4.2 y § 4.3, podemos sacar una conclusión importante: @PostConstruct se ejecuta antes que el método afterPropertiesSet(), y afterPropertiesSet() se ejecuta antes que el método Custom Init , como se muestra en la figura a continuación.

init_mtd_sequence.png

§ 4.4 applyBeanPostProcessorsAfterInitialization()

Como sugiere el nombre, applyBeanPostProcessorsAfterInitialization()los métodos se utilizan para el recorrido BeanPostProcessory sus métodos se llaman durante el recorrido postProcessAfterInitialization().

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }
}
复制代码

Uno de los escenarios de aplicación más conocidos de BeanPostProcessor se utiliza para unir los contenedores Spring AOP y Spring IoC. En Spring AOP, desempeña esta función de puente. AbstractAutoProxyCreatorSi está interesado en el principio de implementación de Spring AOP, puede comenzar con este BeanPostProcessor clase de implementación!

5 resumen

Aunque el autor ha escrito tanto texto, publicado tanto código y dibujado tantas imágenes, no es realista tratar de comprender el proceso de carga de Bean simplemente leyendo un artículo. Todavía necesita leer el código fuente usted mismo. Después de leer el código fuente Durante el proceso, recuerde no entrar en un callejón sin salida, de lo contrario, solo hará que todos no puedan seguir leyendo y pierdan la confianza y el coraje. Esta es la experiencia personal del autor.

Supongo que te gusta

Origin juejin.im/post/7193552611260235836
Recomendado
Clasificación