本文基于 Spring Boot 3.0.0 (Spring 6.0.2),Bean 指的是 Singleton Bean。

微观地说,Bean 加载流程大致有三个阶段,分别是实例化 createBeanInstance() 、特点填充 populateBean() 和 初始化 initializeBean(),当 Bean 加载流程履行结束,Bean 才具有运用条件!对 Bean 加载流程的探究是一段十分折磨的旅程,你预备好了吗?

带你探索 Bean 加载流程

1 写在前面

为了让 Spring IoC 容器正确地完结 Bean 加载流程,有必要要有一个数据模型来承载 Bean 的装备元数据,装备元数据能够告诉 Spring IoC 容器 怎么创立 Bean 实例何时创立 Bean 实例Bean 的生命周期细节 等信息,这个数据模型便是BeanDefinition接口,在其众多完结类中,RootBeanDefinition 最为常用!

在 Spring Boot 中,BeanDefinition 能够归纳为两类:一种是由开发人员声明的,另一种是由官方及第三方起步依靠 starter 组件中声明的,当然这两种 BeanDefinition 一般都是经过注解声明的。为了加载这两种 BeanDefinition,Spring Boot 会首要完结一个名为 org.springframework.context.annotation.internalConfigurationAnnotationProcessorConfigurationClassPostProcessor类型的 Bean 加载流程。ConfigurationClassPostProcessor 完结了BeanDefinitionRegistryPostProcessor接口。

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry);
}

BeanDefinitionRegistryPostProcessor 承继自BeanFactoryPostProcessor接口,后者是一个极其重要的 Spring IoC 拓宽点。

public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);
}

BeanFactoryPostProcessor 常用于与 BeanDefinition 交互,而非与 Bean 实例交互,由于当履行到postProcessBeanFactory()办法时,只是完结了一切 BeanDefinition 的加载罢了,Bean 还没有实例化呢。咱们完全能够经过 BeanFactoryPostProcessor 将某一 BeanDefinition 实例的 beanClass 特点值替换为CGLIB所生成的 Class 实例,这样后期经过该 BeanDefinition 实例所生成的 Bean 实例就得到增强了。

当履行到 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 时序图,如下所示。

带你探索 Bean 加载流程

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

在 createBeanInstance() 办法履行完之后,紧接着履行applyMergedBeanDefinitionPostProcessors()办法,首要是遍历MergedBeanDefinitionPostProcessor并调用其postProcessMergedBeanDefinition()办法。MergedBeanDefinitionPostProcessor 的运用机遇介于 实例化 createBeanInstance() 与 特点填充 populateBean() 之间,为后续 特点填充 populateBean() 和 初始化 initializeBean() 阶段提早缓存LifecycleMetadataInjectionMetadata。MergedBeanDefinitionPostProcessor 接口有三个重要的完结类,如下所示。

带你探索 Bean 加载流程

  • 在 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 是完全有才能破局的。循环依靠能够分为下图中的这两种类型,其他情形的循环依靠都是它们的变体罢了。

带你探索 Bean 加载流程

为了处理循环依靠问题,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 特点填充

带你探索 Bean 加载流程

关于特点填充或许特点注入的概念,咱们或多或少都了解一些,下面就一起来看看它的悉数逻辑吧。

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,详细参考下图。

带你探索 Bean 加载流程

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 为其供给了两个极其重要的完结类,如下图所示。

带你探索 Bean 加载流程

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 实例完结依靠注入的,如下图所示。

带你探索 Bean 加载流程

4 初始化

带你探索 Bean 加载流程

谢天谢地!咱们终于来到了较为轻松的初始化阶段。对@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() 办法呢? 比较重要的有三个,如下所示。

带你探索 Bean 加载流程

下面以两个末节分别对 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()办法同样简略得不得了,它先调用InitializingBean的 afterPropertiesSet() 办法,然后调用 Custom Init Method (便是 @Bean 注解中 initMethod 特点值所指定的办法)。

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);
                }
            }
        }
    }
}

结合 4.2 和 4.3 这两末节内容,咱们能够得出一个重要定论:@PostConstruct 优先于 afterPropertiesSet() 办法履行,而 afterPropertiesSet() 又优先于 Custom Init Method 履行,如下图所示。

带你探索 Bean 加载流程

4.4 applyBeanPostProcessorsAfterInitialization()

顾名思义,applyBeanPostProcessorsAfterInitialization()办法用于遍历BeanPostProcessor,在遍历进程中调用其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;
    }
}

BeanPostProcessor 最广为人知的一个运用场景是用来桥接 Spring AOP 与 Spring IoC 容器,在 Spring AOP 中扮演这一桥接角色的便是AbstractAutoProxyCreator,咱们假如对 Spring AOP 完结原理感兴趣,能够从这个 BeanPostProcessor 完结类下手!

5 总结

尽管笔者写了这么多文字、贴了这么多代码、画了这么多图,但单单靠阅览一篇文章试图搞懂 Bean 加载流程是不太实际的,仍是需求咱们亲自去阅览源码,在阅览源码进程中,切记不要钻牛角尖,否则只会让咱们读不下去,失去信心与勇气,这是笔者的亲自体验。