Spring專題之Bean初始化源碼分析(1)

前言

Spring IOC容器在初始化以後會對容器中非懶加載的,單例的以及非抽象的bean定義進行bean的初始化操做,同時會也涉及到Bean的後置處理器以及DI(依賴注入)等行爲。對於Bean的初始化,Spring是經過第一次調用getBean方法向容器獲取bean實例時進行的。下面的源碼分析也是基於getBean()做爲入口一步步去了解Spring是如何初始化單例Bean的。segmentfault

Bean初始化

咱們知道Spring IOC容器初始化後會對容器中非懶加載的,單例的以及非抽象的bean定義進行bean的初始化操做,因此咱們分析源碼的入口也就是在容器初始化的入口,分析容器初始化後Spring在什麼地方開始第一次的Bean初始化。緩存

在以前的一篇博文Spring專題之IOC源碼分析中有分析到Spring IOC容器初始化的過程,過程源碼以下:session

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            //調用容器準備刷新的方法,獲取容器的當時時間,同時給容器設置同步標識
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            //告訴子類啓動refreshBeanFactory()方法,Bean定義資源文件的載入從
            //子類的refreshBeanFactory()方法啓動
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            //爲BeanFactory配置容器特性,例如類加載器、事件處理器等
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                //爲容器的某些子類指定特殊的BeanPost事件處理器
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                //調用全部註冊的BeanFactoryPostProcessor的Bean
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                //爲BeanFactory註冊BeanPost事件處理器.
                //BeanPostProcessor是Bean後置處理器,用於監聽容器觸發的事件
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                //初始化信息源,和國際化相關.
                initMessageSource();

                // Initialize event multicaster for this context.
                //初始化容器事件傳播器.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                //調用子類的某些特殊Bean初始化方法
                onRefresh();

                // Check for listener beans and register them.
                //爲事件傳播器註冊事件監聽器.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                //初始化全部剩餘的單例Bean
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                //初始化容器的生命週期事件處理器,併發布容器的生命週期事件
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                //銷燬已建立的Bean
                destroyBeans();

                // Reset 'active' flag.
                //取消refresh操做,重置容器的同步標識.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

上述源碼能夠觀察看在IOC容器被初始化後進行了不少其餘的操做,但這些如今咱們暫時不關心,咱們須要關注的只有finishBeanFactoryInitialization這個方法,這個方法的做用就是初始化全部剩餘的單例Bean,因此這也是咱們如下分析源碼的入口。併發

finishBeanFactoryInitialization方法源碼以下:app

//對配置了lazy-init屬性的Bean進行預實例化處init屬性的Bean進行預實例化處理理
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        ....

        // Instantiate all remaining (non-lazy-init) singletons.
        //對配置了lazy-init屬性的單態模式Bean進行預實例化處理
        beanFactory.preInstantiateSingletons();
    }

這個方法前面一些處理暫時不看,能夠知道最後調用了ConfigurableListableBeanFactory的preInstantiateSingletons方法,也就是對配置了lazy-init屬性的單態模式Bean進行預實例化處理。
下面進入preInstantiateSingletons方法分析,源碼以下:源碼分析

//對配置lazy-init屬性單態Bean的預實例化
    public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Pre-instantiating singletons in " + this);
        }

        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

        for (String beanName : beanNames) {
            //獲取指定名稱的Bean定義
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            //Bean不是抽象的,是單態模式的,且lazy-init屬性配置爲false
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                //若是指定名稱的bean是建立容器的Bean
                if (isFactoryBean(beanName)) {
                    //FACTORY_BEAN_PREFIX=」&」,當Bean名稱前面加」&」符號
                    //時,獲取的是產生容器對象自己,而不是容器產生的Bean.
                    //調用getBean方法,觸發容器對Bean實例化和依賴注入過程
                    final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
                    //標識是否須要預實例化
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        //一個匿名內部類
                        isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
                                ((SmartFactoryBean<?>) factory).isEagerInit(),
                                getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        //調用getBean方法,觸發容器對Bean實例化和依賴注入過程
                        getBean(beanName);
                    }
                }
                else {
                    //調用getBean方法,觸發容器對Bean實例化和依賴注入過程
                    getBean(beanName);
                }
            }
        }

        //觸發bean初始化後的回調
        ...
    }

經過源碼解析,咱們能夠看到這裏對於不是抽象的,是單態模式的,且lazy-init屬性配置爲false的Bean定義進行初始化,而初始化過程正是調用了getBean方法。下面咱們進入getBean方法觀察Spring對bean的初始化過程。getBean方法及相關調用源碼以下:post

//獲取IOC容器中指定名稱的Bean
    public Object getBean(String name) throws BeansException {
        //doGetBean纔是真正向IoC容器獲取被管理Bean的過程
        return doGetBean(name, null, null, false);
    }
    //真正實現向IOC容器獲取Bean的功能,也是觸發依賴注入功能的地方
    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        //根據指定的名稱獲取被管理Bean的名稱,剝離指定名稱中對容器的相關依賴,若是指定的是別名,將別名轉換爲規範的Bean名稱
        final String beanName = transformedBeanName(name);
        Object bean;

        //先從緩存中取是否已經有被建立過的單態類型的Bean,對於單例模式的Bean整個IOC容器中只建立一次,不須要重複建立
        Object sharedInstance = getSingleton(beanName);
        //IOC容器建立單例模式Bean實例對象
        if (sharedInstance != null && args == null) {
            if (logger.isDebugEnabled()) {
                //若是指定名稱的Bean在容器中已有單例模式的Bean被建立
                //直接返回已經建立的Bean
                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 + "'");
                }
            }
            //獲取給定Bean的實例對象,主要是完成FactoryBean的相關處理。注意:BeanFactory是管理容器中Bean的工廠,而FactoryBean是建立建立對象的工廠Bean,二者之間有區別
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            //緩存沒有正在建立的單例模式Bean,緩存中已經有已經建立的原型模式Bean,可是因爲循環引用的問題致使實例化對象失敗
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            //對IOC容器中是否存在指定名稱的BeanDefinition進行檢查,首先檢查是否能在當前的BeanFactory中獲取的所須要的Bean,若是不能則委託當前容器的父級容器去查找,若是仍是找不到則沿着容器的繼承體系向父級容器查找
            BeanFactory parentBeanFactory = getParentBeanFactory();
            //當前容器的父級容器存在,且當前容器中不存在指定名稱的Bean
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                //解析指定Bean名稱的原始名稱
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                            nameToLookup, requiredType, args, typeCheckOnly);
                }
                else if (args != null) {
                    //委派父級容器根據指定名稱和顯式的參數查找
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    //委派父級容器根據指定名稱和類型查找
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

            //建立的Bean是否須要進行類型驗證,通常不須要
            if (!typeCheckOnly) {
                //向容器標記指定的Bean已經被建立
                markBeanAsCreated(beanName);
            }

            try {
                //根據指定Bean名稱獲取其父級的Bean定義
                //主要解決Bean繼承時子類合併父類公共屬性問題
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);
                //獲取當前Bean全部依賴Bean的名稱
                String[] dependsOn = mbd.getDependsOn();
                //若是當前Bean有依賴Bean
                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 + "'");
                        }
                        //遞歸調用getBean方法,獲取當前Bean的依賴Bean
                        registerDependentBean(dep, beanName);
                        //把被依賴Bean註冊給當前依賴的Bean
                        getBean(dep);
                    }
                }
                //建立單例模式Bean的實例對象
                if (mbd.isSingleton()) {
                    //這裏使用了一個匿名內部類,建立Bean實例對象,而且註冊給所依賴的對象
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            //建立一個指定Bean實例對象,若是有父級繼承,則合併子類和父類的定義
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            //顯式地從容器單例模式Bean緩存中清除實例對象
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    //獲取給定Bean的實例對象
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

                //IOC容器建立原型模式Bean實例對象
                else if (mbd.isPrototype()) {
                    //原型模式(Prototype)是每次都會建立一個新的對象
                    Object prototypeInstance = null;
                    try {
                        //回調beforePrototypeCreation方法,默認的功能是註冊當前建立的原型對象
                        beforePrototypeCreation(beanName);
                        //建立指定Bean對象實例
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        //回調afterPrototypeCreation方法,默認的功能告訴IOC容器指定Bean的原型對象再也不建立
                        afterPrototypeCreation(beanName);
                    }
                    //獲取給定Bean的實例對象
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

                //要建立的Bean既不是單例模式,也不是原型模式,則根據Bean定義資源中配置的生命週期範圍,選擇實例化Bean的合適方法,這種在Web應用程序中,比較經常使用,如:request、session、application等生命週期
                else {
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    //Bean定義資源中沒有配置生命週期範圍,則Bean定義不合法
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                    try {
                        //這裏又使用了一個匿名內部類,獲取一個指定生命週期範圍的實例
                        Object scopedInstance = scope.get(beanName, () -> {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        });
                        //獲取給定Bean的實例對象
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {
                        ...
                    }
                }
            }
            catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }

        //對建立的Bean實例對象進行類型檢查
        if (requiredType != null && !requiredType.isInstance(bean)) {
            try {
                T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
                if (convertedBean == null) {
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
                return convertedBean;
            }
            catch (TypeMismatchException ex) {
                ...
            }
        }
        return (T) bean;
    }

這裏經過上述源碼的分析,總結如下Spring初始化bean的過程,首先Spring會去緩存中搜索是否已存在bean實例,若是存在則直接取出返回,不存在就判斷是否存在父容器,存在則調用父容器的getBean方法進行初始化,不然經過判斷bean定義是不是單例bean,是不是原型bena進行相關的初始化操做,能夠知道最後都是調用了createBean方法去建立bean的。ui

至此,經過上述的源碼分析,咱們對Spring在IOC初始化後對bean的初始化過程有了大體的瞭解,下篇博客會繼續這篇經過源碼分析Spring初始化的具體過程。this

相關文章
相關標籤/搜索