zoukankan      html  css  js  c++  java
  • Spring IOC容器创建bean过程浅析

    1. 背景

    Spring框架本身非常庞大,源码阅读可以从Spring IOC容器的实现开始一点点了解。然而即便是IOC容器,代码仍然是非常多,短时间内全部精读完并不现实
    本文分析比较浅,而完整的IOC创建bean实际上是非常复杂的。本文对于BeanDefinition的加载解析,bean实例化的反射调用细节不作介绍,仅以较为粗略的角度来大体感受IOC容器创建bean的过程。

    本文涉及的Spring源码版本为4.3.5.RELEASE。

    2. 想要了解什么

    下面就抛出几个想要了解的问题,也是本文介绍所要围绕的关键点。

    • BeanFactory和ApplicationContext的区别
    • IOC容器创建Bean的大致过程
    • Bean的循环依赖是如何解决的
    • 那些Aware究竟是什么

    3. 从源码中找出问题的答案

    3.1 BeanFactory & ApplicationContext

    3.1.1 BeanFactory体系

    org.springframework.beans.factory.BeanFactory是Spring的Bean容器的一个非常基本的接口,位于spring-beans模块。它包括了各种getBean方法,如通过名称、类型、参数等,试图从Bean容器中返回一个Bean实例。还包括诸如containsBean, isSingleton, isPrototype等方法判断Bean容器中是否存在某个Bean或是判断Bean是否为单例/原型等等。


    可以看到BeanFactory向下主要有三条继承路线

    • ListableBeanFactory
      在BeanFactory基础上,支持对Bean容器中Bean的枚举。
    • HierarchicalBeanFactory -> ConfigurableBeanFactory
      HierarchicalBeanFactory有个getParentBeanFactory方法,使得Bean容器具有亲缘关系。而ConfigurableBeanFactory则是对BeanFactory的一系列配置功能提供了支持。
    • AutowireCapableBeanFactory
      提供了一系列用于自动装配Bean的方法,用户代码比较少用到,更多是作为Spring内部使用。

    3.1.2 ApplicationContext体系

    org.springframework.context.ApplicationContext是Spring上下文的底层接口,位于spring-context模块。它可以视作是Spring IOC容器的一种高级形式,也是我们用Spring企业开发时必然会用到的接口,它含有许多面向框架的特性,也对应用环境作了适配。

    从上面的图中,我们可以看到ApplicationContext作为BeanFactory的子接口,与BeanFactory之间也是通过HierarchicalBeanFactory与ListableBeanFactory桥接的。
    ApplicationContext接口,继承了MessageSource, ResourceLoader, ApplicationEventPublisher接口,以BeanFactory为主线添加了许多高级容器特性。

    3.2 Spring创建Bean的大致过程

    搞清楚整个Spring IOC容器创建Bean的过程,对于阅读源码的效率会有很大的提升。
    下面梳理一下整个过程:

    1. 实例化BeanFactoryPostProcessor实现类
    2. 调用BeanFactoryPostProcessor#postProcessBeanFactory
    3. 实例化BeanPostProcessor实现类
    4. 调用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
    5. 实例化Bean
    6. 调用InstantiationAwareBeanProcessor#postProcessAfterInstantiation
    7. 调用InstantiationAwareBeanPostProcessor#postProcessPropertyValues
    8. 为Bean注入属性
    9. 调用BeanNameAware#setBeanName
    10. 调用BeanClassLoaderAware#setBeanClassLoader
    11. 调用BeanFactoryAware#setBeanFactory
    12. 调用BeanPostProcessor#postProcessBeforeInitialization
    13. 调用InitializingBean#afterPropertiesSet
    14. 调用Bean的init-method
    15. 调用BeanPostProcessor#postProcessAfterInitialization

    3.3 IOC容器依赖注入

    完整来说,IOC容器的初始化过程中做了在容器中建立BeanDefinition的数据映射。之后所有的依赖的注入都依托于已经存在的BeanDefinition,限于篇幅,此处略去对BeanDefinition的建立作介绍。直接从上下文的getBean开始看起。

    在AbstractApplicationContext抽象类中有一个getBeanFactory方法用于返回一个ConfigurableListableBeanFactory,所有BeanFactory接口的方法实际上都委托给子类内部的ConfigurableListableBeanFactory实现。

    我们以AnnotationConfigApplicationContext,它在被构造时,内部的beanFactory实际上是由父类GenericApplicationContext来初始化一个DefaultListableBeanFactory的。

    因此我们看某个bean是如何被加载的可以从DefaultListableBeanFactory的getBean方法看起,对于DefaultListableBeanFactory而言那些getBean方法实际上在AbstractBeanFactory这一层就都已经实现了,并且都委托给了AbstractBeanFactory#doGetBean。下面就来看一下doGetBean方法。

    protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
            throws BeansException {
    
        final String beanName = transformedBeanName(name);
        Object bean;
    
        /*
         * 尝试从缓存中拿取一个bean实例。
         * Spring会在Bean还没完全初始化完毕的前,通过一个ObjectFactory提前暴露出bean实例,这样为解决循环依赖提供了遍历。
         */
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            if (logger.isDebugEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                }
                else {
                    logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
            // 对FactoryBean的情况进行特殊处理。
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }
    
        else {
            // 如果正在创建的bean为原型并且已经正在创建,这种循环依赖是无法解决的,要抛出异常。
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }
    
            // 如果该beanFactory中不包含要创建bean的beanDefinition,则尝试从父beanFactory中寻找。
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                String nameToLookup = originalBeanName(name);
                if (args != null) {
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }
    
            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }
    
            try {
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);
    
                // 有些bean是有depends-on/@DependsOn的,需要先初始化这些依赖。
                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);
                        getBean(dep);
                    }
                }
    
                // 创建单例bean。
                if (mbd.isSingleton()) {
                    /*
                     * 调用父类DefaultSingletonBeanRegistry的getSingleton,具体创建bean的工作实际上仍然是
                     * 回调参数中传递的ObjectFactory#getObject方法,而createBean实际上是子类AbstractAutowireCapableBeanFactory实现的。
                     */
                    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            catch (BeansException ex) {
                                destroySingleton(beanName);
                                throw ex;
                            }
                        }
                    });
                    // 对FactoryBean的情况进行特殊处理。
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
                // 创建原型bean。
                else if (mbd.isPrototype()) {
                    Object prototypeInstance = null;
                    try {
                        // 前置处理,维护prototypesCurrentlyInCreation,加入当前bean记录。
                        beforePrototypeCreation(beanName);
                        // 委托给子类AbstractAutowireCapableBeanFactory来完成具体的创建bean工作。
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        // 后置处理,维护prototypesCurrentlyInCreation信息,删除当前bean记录。
                        afterPrototypeCreation(beanName);
                    }
                    // 对FactoryBean的情况进行特殊处理。
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }
    
                else {
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                    try {
                        Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                            @Override
                            public Object getObject() throws BeansException {
                                beforePrototypeCreation(beanName);
                                try {
                                    return createBean(beanName, mbd, args);
                                }
                                finally {
                                    afterPrototypeCreation(beanName);
                                }
                            }
                        });
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {
                        throw new BeanCreationException(beanName,
                                "Scope '" + scopeName + "' is not active for the current thread; consider " +
                                "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                                ex);
                    }
                }
            }
            catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }
    
        // 到这里一个bean就已经创建完了,最后一步检查类型,如果不匹配会尝试转换。
        if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
            try {
                return getTypeConverter().convertIfNecessary(bean, requiredType);
            }
            catch (TypeMismatchException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Failed to convert bean '" + name + "' to required type '" +
                            ClassUtils.getQualifiedName(requiredType) + "'", ex);
                }
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        }
        return (T) bean;
    }
    

    上面针对AbstractBeanFactory#doGetBean方法进行了源码分析,从中我们可以看出它主要会干这几件事情:

    1. 转换beanName。
    2. 尝试从缓存的单例中拿实例。
    3. 如果要创建的bean是原型模式,且已经在尝试创建,这种循环依赖是无法解决的。
    4. 当前beanFactory不包含要创建的bean的beanDefinition,会尝试从parentBeanFactory中获取。
    5. 如果当前bean有依赖(xml的话就是有depends-on,注解的话有@DependsOn),则需要先完成那些bean的创建初始化。
    6. 针对scope分类讨论创建。我们比较关心的就是单例,其次是原型。
    7. 类型检查,并且尝试转换。

    我们一般比较关心的就是单例bean和原型bean的创建。
    在获取单例bean时doGetBean方法会调用父类DefaultSingletonBeanRegistry#getSingleton。可以把DefaultSingletonBeanRegistry当作一个“单例bean桶”,因为它确实就是一个用来存放单例bean的桶。但是这个桶本身不关心bean到底该怎么创建,所以对于桶里还没有的bean,它将创建bean的职责通过回调ObjectFactory#getObject来完成,而AbstractBeanFactory中传递给getSingleton方法的ObjectFactory#getObject的具体实现是调用createBean,这个方法是真正创建并初始化bean的方法,由子类AbstractAutowireCapableBeanFactory完成。
    对于获取原型bean则简单多了,不用关心放到桶里缓存的事情,直接调用createBean创建就是了。

    所以我们接下来通过AbstractAutowireCapableBeanFactory来看一下一个Bean具体是如何创建并初始化的。

    protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;
    
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }
    
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }
    
        try {
            /* 
             * 在对象被实例化前,这里有一个短路逻辑,会调用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation。
             * 如果存在某个InstantiationAwareBeanPostProcessor的调用结果不为null,则形成了短路,接下来调用BeanPostProcessor#postProcessAfterInitialization。
             *
             * 实际上,一般Spring里默认就LazyInitTargetSourceCreator和QuickTargetSourceCreator可能会使得这里的短路生效。
             * 大部分情况AOP还是在bean被正常实例化后通过调用postProcessAfterInitialization实现的。
             */
            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);
        }
    
        // 创建bean的主要方法。
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
    

    从上面可以看到AbstractAutowireCapableBeanFactory#createBean是创建bean的主要入口方法,但仍然不是最主要在“干活”的方法。继续向下看doCreateBean方法。

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException {
    
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            // 尝试从factoryBean缓存中获取。
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            // 创建bean实例。
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
    
        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.postProcessed = true;
            }
        }
    
        /*
         * Spring为了解决单例bean的循环引用问题,会在bean还没有完全初始化完毕前通过添加singletonFactory
         * 使得其它bean可以拿到某个bean的实例引用。
         */
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }
    
        // 接下去初始化bean。
        Object exposedObject = bean;
        try {
            // 填充bean中的属性。
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {
                /*
                 * 调用初始化方法,比如:
                 * 1. 各种aware回调
                 * 2. 调用BeanPostProcessor#postProcessBeforeInitialization
                 * 3. 调用InitializingBean#afterPropertiesSet, xml中的init-method
                 * 4. 调用BeanPostProcessor#postProcessAfterInitialization
                 */
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }
    
        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            /*
             * 上面的getSingleton第二个参数为false表示不会主动触发early reference的创建。
             * 所以此处earlySingletonReference只有在bean创建过程中发现有别的bean与当前bean有循环依赖才不为空。
             */
            if (earlySingletonReference != null) {
                /*
                 * 如果当前bean调用initializeBean没有增强原始bean实例,则取earlySingletonReference。
                 * 
                 * 举例:
                 * BeanA与BeanB互相依赖。Srping先创建BeanA,再创建BeanB。
                 * BeanA通过addSingletonFactory暴露了获取BeanA引用的途径。
                 *
                 * 在populateBean的时候需要注入BeanB,而BeanB又需要注入BeanA,
                 * 则在获取BeanA时会调用原先BeanA暴露的ObjectFactory,继而使得earlySingletonObjects中加入了BeanA引用。
                 *
                 * 回到BeanA的创建过程,走到此步时,发现initializeBean没有增强原始bean实例,
                 * 则需要取其它循环依赖bean拿BeanA时在registry留下的结果(原始bean经过SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference回调)。
                 */
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    // 获取当前bean依赖的其它bean。
                    String[] dependentBeans = getDependentBeans(beanName);
                    // 过滤筛选出真正依赖的bean。
                    Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    /*
                     * 举例:
                     * BeanA与BeanB互相依赖。Srping先创建BeanA,再创建BeanB。
                     * BeanA的创建走到这里时会抛出异常。
                     *
                     * 原因是上面的exposedObject != bean说明initializeBean方法的调用增强了原始的BeanA。
                     * 而BeanB中注入的BeanA很可能是原始beanA(可能会有SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference回调,
                     * 也就是BeanB中注入的BeanA不是此处BeanA的最终版exposedObject。
                     */
                    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 " +
                                "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }
    
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }
    
        return exposedObject;
    }
    

    3.4 Bean的循环依赖是如何解决的

    不是所有的循环依赖Spring都能够解决的。

    • 对于最简单的情况,bean为单例,且使用Autowired或者setter注入,Spring是可以解决这样的循环依赖的。通过上面的代码中我们可以看出,在一个Bean实例化后,会调用addSingletonFactory方法,在IOC容器中通过一个ObjectFactory暴露出可以获取还未完全初始化完毕的bean引用。若存在循环依赖,则依赖的bean可以在调用getBean时通过getSingleton方法获取到循环依赖的bean。

    • 但是Spring是不允许出现原型环的,举例来说,BeanA和BeanB循环依赖且scope都为prototype。因为prototype的bean,不会触发addSingletonFactory,即每次get这样的bean都会新创建一个。所以创建BeanA需要注入一个BeanB,而这个BeanB又需要注入一个新的BeanA,这样的循环依赖是没办法解决的。Spring会判断当前bean是否是prototype并且已经在创建中,然后抛出异常。

    • 对于构造器依赖,可以作一下讨论,下面讨论的bean的scope都为单例

      • 如果BeanA构造器中依赖BeanB,并且BeanA先创建,则无论BeanB以哪种形式依赖BeanA,都没办法解决这样的循环依赖。因为实例化BeanA需要先得到BeanB(此时还未提前暴露引用),BeanB依赖BeanA,但是拿不到BeanA提前暴露的引用,这就形成了无限循环。这种情况会在BeanB试图获取BeanA时在beforeSingletonCreation方法抛出异常。
      • 如果BeanA非构造器依赖BeanB,并且BeanA先创建,BeanB即使构造器依赖BeanA,也可以进行解决循环依赖。 因为这种情况BeanB可以拿到BeanA提前暴露的引用。

    3.5 那些Aware究竟是什么

    Spring中有很多XXXAware接口,从字面意思上很容易理解:就是bean能够“感知”XXX。通常这些接口的方法都是setXXX。在项目里做一个工具类实现ApplicationContextAware接口,里面可以塞一个ApplicationContext实例到静态域中,在代码中就可以很方便获取到Spring上下文进行一些操作。

    那么Spring对于这些Aware接口是在哪一步调用的呢?答案其实在上面的源码分析中已经提到。在AbstractAutowireCapableBeanFactory#initializeBean方法中,Spring默认会对实现BeanNameAware, BeanClassLoaderAware, BeanFactoryAware进行回调,为它们注入beanName, classLoader, beanFactory等。

    而对于更多的一些扩展,Spring基于那些processor实现了很强的可拓展性与可插拔性。比如我们非常熟悉的ApplicationContextAware接口实际上是通过ApplicationContextAwareProcessor来实际调用的,它继承了BeanPostProcessor,其中postProcessBeforeInitialization方法中会对EnvironmentAware, EmbeddedValueResolverAware, ApplicationContextAware等等一系列Aware接口的子类Bean进行回调,为其注入相关资源。

    那么ApplicationContextAwareProcessor是什么时候出现在BeanPostProcessor集合中的呢?在AbstractApplicationContext#prepareBeanFactory方法中,Spring有如下代码:

    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    

    也就是当Spring上下文在初始化prepareBeanFactory的时候就已经添加了ApplicationContextAwareProcessor。

  • 相关阅读:
    MRC与ARC两种模式的相互兼容
    解决获取的手机序列号卸载应用重新安装时序列号变动的问题
    屏幕截图
    图片右下角显示水印
    在一个工程中建两个端口(司机端和货主端)
    左右侧边栏抽屉效果
    第二阶段第一天站立会议总结
    第十天站立会议总结
    第九天站立会议总结
    第八天站立会议总结
  • 原文地址:https://www.cnblogs.com/micrari/p/7354650.html
Copyright © 2011-2022 走看看