成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

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

harryhappy / 1539人閱讀

摘要:初始化我們知道容器初始化后會(huì)對(duì)容器中非懶加載的,單例的以及非抽象的定義進(jìn)行的初始化操作,所以我們分析源碼的入口也就是在容器初始化的入口,分析容器初始化后在什么地方開(kāi)始第一次的初始化。

前言

Spring IOC容器在初始化之后會(huì)對(duì)容器中非懶加載的,單例的以及非抽象的bean定義進(jìn)行bean的初始化操作,同時(shí)會(huì)也涉及到Bean的后置處理器以及DI(依賴注入)等行為。對(duì)于Bean的初始化,Spring是通過(guò)第一次調(diào)用getBean方法向容器獲取bean實(shí)例時(shí)進(jìn)行的。下面的源碼分析也是基于getBean()作為入口一步步去了解Spring是如何初始化單例Bean的。

Bean初始化

我們知道Spring IOC容器初始化后會(huì)對(duì)容器中非懶加載的,單例的以及非抽象的bean定義進(jìn)行bean的初始化操作,所以我們分析源碼的入口也就是在容器初始化的入口,分析容器初始化后Spring在什么地方開(kāi)始第一次的Bean初始化。

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

    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            //調(diào)用容器準(zhǔn)備刷新的方法,獲取容器的當(dāng)時(shí)時(shí)間,同時(shí)給容器設(shè)置同步標(biāo)識(shí)
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            //告訴子類啟動(dòng)refreshBeanFactory()方法,Bean定義資源文件的載入從
            //子類的refreshBeanFactory()方法啟動(dòng)
            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.
                //調(diào)用所有注冊(cè)的BeanFactoryPostProcessor的Bean
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                //為BeanFactory注冊(cè)BeanPost事件處理器.
                //BeanPostProcessor是Bean后置處理器,用于監(jiān)聽(tīng)容器觸發(fā)的事件
                registerBeanPostProcessors(beanFactory);

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

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

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

                // Check for listener beans and register them.
                //為事件傳播器注冊(cè)事件監(jiān)聽(tīng)器.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                //初始化所有剩余的單例Bean
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                //初始化容器的生命周期事件處理器,并發(fā)布容器的生命周期事件
                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.
                //銷毀已創(chuàng)建的Bean
                destroyBeans();

                // Reset "active" flag.
                //取消refresh操作,重置容器的同步標(biāo)識(shí).
                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容器被初始化后進(jìn)行了很多其他的操作,但這些現(xiàn)在我們暫時(shí)不關(guān)心,我們需要關(guān)注的只有finishBeanFactoryInitialization這個(gè)方法,這個(gè)方法的作用就是初始化所有剩余的單例Bean,所以這也是我們以下分析源碼的入口。

finishBeanFactoryInitialization方法源碼如下:

    //對(duì)配置了lazy-init屬性的Bean進(jìn)行預(yù)實(shí)例化處init屬性的Bean進(jìn)行預(yù)實(shí)例化處理理
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        ....

        // Instantiate all remaining (non-lazy-init) singletons.
        //對(duì)配置了lazy-init屬性的單態(tài)模式Bean進(jìn)行預(yù)實(shí)例化處理
        beanFactory.preInstantiateSingletons();
    }

這個(gè)方法前面一些處理暫時(shí)不看,可以知道最后調(diào)用了ConfigurableListableBeanFactory的preInstantiateSingletons方法,也就是對(duì)配置了lazy-init屬性的單態(tài)模式Bean進(jìn)行預(yù)實(shí)例化處理。
下面進(jìn)入preInstantiateSingletons方法分析,源碼如下:

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

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

        for (String beanName : beanNames) {
            //獲取指定名稱的Bean定義
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            //Bean不是抽象的,是單態(tài)模式的,且lazy-init屬性配置為false
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                //如果指定名稱的bean是創(chuàng)建容器的Bean
                if (isFactoryBean(beanName)) {
                    //FACTORY_BEAN_PREFIX=”&”,當(dāng)Bean名稱前面加”&”符號(hào)
                    //時(shí),獲取的是產(chǎn)生容器對(duì)象本身,而不是容器產(chǎn)生的Bean.
                    //調(diào)用getBean方法,觸發(fā)容器對(duì)Bean實(shí)例化和依賴注入過(guò)程
                    final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
                    //標(biāo)識(shí)是否需要預(yù)實(shí)例化
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        //一個(gè)匿名內(nèi)部類
                        isEagerInit = AccessController.doPrivileged((PrivilegedAction) () ->
                                ((SmartFactoryBean) factory).isEagerInit(),
                                getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        //調(diào)用getBean方法,觸發(fā)容器對(duì)Bean實(shí)例化和依賴注入過(guò)程
                        getBean(beanName);
                    }
                }
                else {
                    //調(diào)用getBean方法,觸發(fā)容器對(duì)Bean實(shí)例化和依賴注入過(guò)程
                    getBean(beanName);
                }
            }
        }

        //觸發(fā)bean初始化后的回調(diào)
        ...
    }

通過(guò)源碼解析,我們可以看到這里對(duì)于不是抽象的,是單態(tài)模式的,且lazy-init屬性配置為false的Bean定義進(jìn)行初始化,而初始化過(guò)程正是調(diào)用了getBean方法。下面我們進(jìn)入getBean方法觀察Spring對(duì)bean的初始化過(guò)程。getBean方法及相關(guān)調(diào)用源碼如下:

    //獲取IOC容器中指定名稱的Bean
    public Object getBean(String name) throws BeansException {
        //doGetBean才是真正向IoC容器獲取被管理Bean的過(guò)程
        return doGetBean(name, null, null, false);
    }
    //真正實(shí)現(xiàn)向IOC容器獲取Bean的功能,也是觸發(fā)依賴注入功能的地方
    protected  T doGetBean(final String name, @Nullable final Class requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        //根據(jù)指定的名稱獲取被管理Bean的名稱,剝離指定名稱中對(duì)容器的相關(guān)依賴,如果指定的是別名,將別名轉(zhuǎn)換為規(guī)范的Bean名稱
        final String beanName = transformedBeanName(name);
        Object bean;

        //先從緩存中取是否已經(jīng)有被創(chuàng)建過(guò)的單態(tài)類型的Bean,對(duì)于單例模式的Bean整個(gè)IOC容器中只創(chuàng)建一次,不需要重復(fù)創(chuàng)建
        Object sharedInstance = getSingleton(beanName);
        //IOC容器創(chuàng)建單例模式Bean實(shí)例對(duì)象
        if (sharedInstance != null && args == null) {
            if (logger.isDebugEnabled()) {
                //如果指定名稱的Bean在容器中已有單例模式的Bean被創(chuàng)建
                //直接返回已經(jīng)創(chuàng)建的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的實(shí)例對(duì)象,主要是完成FactoryBean的相關(guān)處理。注意:BeanFactory是管理容器中Bean的工廠,而FactoryBean是創(chuàng)建創(chuàng)建對(duì)象的工廠Bean,兩者之間有區(qū)別
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            //緩存沒(méi)有正在創(chuàng)建的單例模式Bean,緩存中已經(jīng)有已經(jīng)創(chuàng)建的原型模式Bean,但是由于循環(huán)引用的問(wèn)題導(dǎo)致實(shí)例化對(duì)象失敗
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            //對(duì)IOC容器中是否存在指定名稱的BeanDefinition進(jìn)行檢查,首先檢查是否能在當(dāng)前的BeanFactory中獲取的所需要的Bean,如果不能則委托當(dāng)前容器的父級(jí)容器去查找,如果還是找不到則沿著容器的繼承體系向父級(jí)容器查找
            BeanFactory parentBeanFactory = getParentBeanFactory();
            //當(dāng)前容器的父級(jí)容器存在,且當(dāng)前容器中不存在指定名稱的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) {
                    //委派父級(jí)容器根據(jù)指定名稱和顯式的參數(shù)查找
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    //委派父級(jí)容器根據(jù)指定名稱和類型查找
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

            //創(chuàng)建的Bean是否需要進(jìn)行類型驗(yàn)證,一般不需要
            if (!typeCheckOnly) {
                //向容器標(biāo)記指定的Bean已經(jīng)被創(chuàng)建
                markBeanAsCreated(beanName);
            }

            try {
                //根據(jù)指定Bean名稱獲取其父級(jí)的Bean定義
                //主要解決Bean繼承時(shí)子類合并父類公共屬性問(wèn)題
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);
                //獲取當(dāng)前Bean所有依賴Bean的名稱
                String[] dependsOn = mbd.getDependsOn();
                //如果當(dāng)前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 + """);
                        }
                        //遞歸調(diào)用getBean方法,獲取當(dāng)前Bean的依賴Bean
                        registerDependentBean(dep, beanName);
                        //把被依賴Bean注冊(cè)給當(dāng)前依賴的Bean
                        getBean(dep);
                    }
                }
                //創(chuàng)建單例模式Bean的實(shí)例對(duì)象
                if (mbd.isSingleton()) {
                    //這里使用了一個(gè)匿名內(nèi)部類,創(chuàng)建Bean實(shí)例對(duì)象,并且注冊(cè)給所依賴的對(duì)象
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            //創(chuàng)建一個(gè)指定Bean實(shí)例對(duì)象,如果有父級(jí)繼承,則合并子類和父類的定義
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            //顯式地從容器單例模式Bean緩存中清除實(shí)例對(duì)象
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    //獲取給定Bean的實(shí)例對(duì)象
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

                //IOC容器創(chuàng)建原型模式Bean實(shí)例對(duì)象
                else if (mbd.isPrototype()) {
                    //原型模式(Prototype)是每次都會(huì)創(chuàng)建一個(gè)新的對(duì)象
                    Object prototypeInstance = null;
                    try {
                        //回調(diào)beforePrototypeCreation方法,默認(rèn)的功能是注冊(cè)當(dāng)前創(chuàng)建的原型對(duì)象
                        beforePrototypeCreation(beanName);
                        //創(chuàng)建指定Bean對(duì)象實(shí)例
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        //回調(diào)afterPrototypeCreation方法,默認(rèn)的功能告訴IOC容器指定Bean的原型對(duì)象不再創(chuàng)建
                        afterPrototypeCreation(beanName);
                    }
                    //獲取給定Bean的實(shí)例對(duì)象
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

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

        //對(duì)創(chuàng)建的Bean實(shí)例對(duì)象進(jìn)行類型檢查
        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;
    }

這里通過(guò)上述源碼的分析,總結(jié)以下Spring初始化bean的過(guò)程,首先Spring會(huì)去緩存中搜索是否已存在bean實(shí)例,如果存在則直接取出返回,不存在就判斷是否存在父容器,存在則調(diào)用父容器的getBean方法進(jìn)行初始化,否則通過(guò)判斷bean定義是否是單例bean,是否是原型bena進(jìn)行相關(guān)的初始化操作,可以知道最后都是調(diào)用了createBean方法去創(chuàng)建bean的。

至此,通過(guò)上述的源碼分析,我們對(duì)Spring在IOC初始化后對(duì)bean的初始化過(guò)程有了大致的了解,下篇博客會(huì)繼續(xù)這篇通過(guò)源碼分析Spring初始化的具體過(guò)程。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/77002.html

相關(guān)文章

  • Spring專題Bean始化源碼分析(2)

    摘要:前言這篇是專題初始化的第二篇,主要對(duì)初始化具體過(guò)程的源碼分析。上篇博客專題之初始化源碼分析中我們對(duì)如何開(kāi)始初始化以及初始化的總體過(guò)程有了大致的了解,接下來(lái)就繼續(xù)上篇博客的結(jié)尾處開(kāi)始來(lái)分析初始化的具體過(guò)程。 前言 這篇是Spring專題Bean初始化的第二篇,主要對(duì)bean初始化具體過(guò)程的源碼分析。上篇博客Spring專題之Bean初始化源碼分析(1)中我們對(duì)Spring如何開(kāi)始初始化b...

    Pikachu 評(píng)論0 收藏0
  • Spring專題IOC源碼分析

    摘要:前言以下源碼基于版本解析。實(shí)現(xiàn)源碼分析對(duì)于的實(shí)現(xiàn),總結(jié)來(lái)說(shuō)就是定位加載和注冊(cè)。定位就是需要定位配置文件的位置,加載就是將配置文件加載進(jìn)內(nèi)存注冊(cè)就是通過(guò)解析配置文件注冊(cè)。下面我們從其中的一種使用的方式一步一步的分析的實(shí)現(xiàn)源碼。 前言 以下源碼基于Spring 5.0.2版本解析。 什么是IOC容器? 容器,顧名思義可以用來(lái)容納一切事物。我們平常所說(shuō)的Spring IOC容器就是一個(gè)可以容...

    不知名網(wǎng)友 評(píng)論0 收藏0
  • Spring注解專題系類(二)

    摘要:的在單例被破壞時(shí)由進(jìn)行方法調(diào)用。定義并實(shí)現(xiàn)這兩個(gè)接口容器創(chuàng)建完成注解是的縮寫,意思是規(guī)范提案。在創(chuàng)建完成并且屬性賦值完成來(lái)執(zhí)行初始化方法在容器銷毀之前回調(diào)通知支持自動(dòng)裝配,類似。 Spring注解應(yīng)用篇--IOC容器Bean生命周期 這是Spring注解專題系類文章,本系類文章適合Spring入門者或者原理入門者,小編會(huì)在本系類文章下進(jìn)行企業(yè)級(jí)應(yīng)用實(shí)戰(zhàn)講解以及spring源碼跟進(jìn)。本文...

    Alex 評(píng)論0 收藏0
  • 慕課網(wǎng)_《Spring入門篇》學(xué)習(xí)總結(jié)

    摘要:入門篇學(xué)習(xí)總結(jié)時(shí)間年月日星期三說(shuō)明本文部分內(nèi)容均來(lái)自慕課網(wǎng)。主要的功能是日志記錄,性能統(tǒng)計(jì),安全控制,事務(wù)處理,異常處理等等。 《Spring入門篇》學(xué)習(xí)總結(jié) 時(shí)間:2017年1月18日星期三說(shuō)明:本文部分內(nèi)容均來(lái)自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)示例源碼:https://github.com/zccodere/s...個(gè)人學(xué)習(xí)源碼:https://git...

    Ververica 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<