Spring源碼深度解析容器的擴(kuò)展功能(轉(zhuǎn)載)

經(jīng)過(guò)之前的分析丐一,我們已經(jīng)了解了Spring是如何解析和加載的bean的。但是在上一篇文章結(jié)束的時(shí)候說(shuō)到庸疾,一般我們寫(xiě)程序是不會(huì)用到BeanFactory來(lái)當(dāng)做Spring的容器的仓手,一般使用的是ApplicationContext作為Spring的容器睡互。這兩者之間有什么區(qū)別呢?

ApplicationContext和BeanFactory在Spring中都是用于加載bean的舰涌,但是ApplicationContext提供了許多擴(kuò)展功能猖任,換句話說(shuō),BeanFactory有的功能ApplicationContext全都有瓷耙,而Application有的功能朱躺,BeanFactory卻不一定有,所有在一般情況下我們寫(xiě)程序用到的都是ApplicationContext作為Spring的容器哺徊。

那么室琢,ApplicationContext比BeanFactory多出了哪些功能呢?這就是我們下面要關(guān)注的問(wèn)題落追。

首先盈滴,我們首先來(lái)看一看這兩個(gè)不同的類在加載配置文件上的寫(xiě)法的不同:

使用BeanFactory方式加載XML

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));

使用ApplicationContext方式加載XML

ApplicationContext bf = new ClassPathXmlApplicationContext("beanFactoryTest.xml");

與之前研究BeanFactory一樣,我們這次還是從ClassPathXmlApplication作為切入點(diǎn)轿钠,開(kāi)始對(duì)整體功能進(jìn)行分析

package org.springframework.context.support;
 
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }
 
    public ClassPathXmlApplicationContext(
            String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
            throws BeansException {
 
        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }
}

設(shè)置路徑是必不可少的步驟巢钓,ClassPathXmlApplicationContext中可以將配置文件路徑以數(shù)組的方式傳入,ClassPathXmlApplicationContext可以對(duì)數(shù)組進(jìn)行解析并進(jìn)行加載疗垛。而對(duì)于解析及功能的實(shí)現(xiàn)都在refresh()中實(shí)現(xiàn)症汹。

設(shè)置配置路徑

在ClassPathXmlApplicationContext中支持多個(gè)配置文件以數(shù)組方式同時(shí)傳入:

    public void setConfigLocations(@Nullable String... locations) {
        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];
            for (int i = 0; i < locations.length; i++) {
                //解析給定路徑
                this.configLocations[i] = resolvePath(locations[i]).trim();
            }
        }
        else {
            this.configLocations = null;
        }
    }

此函數(shù)主要用于解析給定的路徑數(shù)組,當(dāng)然贷腕,如果數(shù)組中包含特殊符號(hào)背镇,如${var}咬展,那么在resolvePath中會(huì)搜索匹配的系統(tǒng)變量并替換

擴(kuò)展功能

設(shè)置了路徑之后,便可以根據(jù)路徑做配置文件的解析以及各種功能的實(shí)現(xiàn)了瞒斩∑破牛可以說(shuō)refresh函數(shù)中幾乎包含了ApplicationContext中提供的全部功能,而且此函數(shù)中邏輯非常清楚明了胸囱,使我們很容易分析對(duì)應(yīng)的層次及邏輯祷舀。

    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            //準(zhǔn)備刷新的上下文環(huán)境
            prepareRefresh();
 
            //初始化BeanFactory,并進(jìn)行XML文件讀取
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 
            //對(duì)BeanFactory進(jìn)行各種 功能填充
            prepareBeanFactory(beanFactory);
 
            try {
                //子類覆蓋方法做額外的處理
                postProcessBeanFactory(beanFactory);
 
                //激活各種BeanFactory處理器
                invokeBeanFactoryPostProcessors(beanFactory);
 
                //注冊(cè)攔截Bean創(chuàng)建的Bean處理器烹笔,這里只是注冊(cè)裳扯,真正的調(diào)用是在getBean的時(shí)候
                registerBeanPostProcessors(beanFactory);
 
                //為上下文初始化Message源,即不同語(yǔ)言的消息體谤职,國(guó)際化處理
                initMessageSource();
 
                //初始化應(yīng)用消息廣播器饰豺,并放入"applicationEventMulticaster"bean中
                initApplicationEventMulticaster();
 
                //留給子類來(lái)初始化其他的bean
                onRefresh();
 
                //在所有注冊(cè)的bean中查找Listener bean,注冊(cè)到消息廣播中
                registerListeners();
 
                //初始化剩下的單實(shí)例(非惰性的)
                finishBeanFactoryInitialization(beanFactory);
 
                //完成刷新過(guò)程柬帕,通知生命周期處理器lifecycleProcessor刷新過(guò)程哟忍,同時(shí)發(fā)出ContextRefreshEvent通知?jiǎng)e人
                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.
                destroyBeans();
 
                // Reset 'active' flag.
                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();
            }
        }
    }

下面概括一下ClassPathXmlApplicationContext初始化的步驟,并從中解釋一下它為我們提供的功能陷寝。

(1)初始化前的準(zhǔn)備工作锅很,例如對(duì)系統(tǒng)屬性或者環(huán)境變量進(jìn)行準(zhǔn)備及驗(yàn)證:在某種情況下項(xiàng)目的使用需要讀取某些系統(tǒng)變量,而這個(gè)變量的設(shè)置很可能會(huì)影響著系統(tǒng)的正確性凤跑,那么ClassPathXmlApplicationContext為我們提供的這個(gè)準(zhǔn)備函數(shù)就顯得非常必要爆安,它可以在Spring啟動(dòng)的時(shí)候提前對(duì)必須的變量進(jìn)行存在性驗(yàn)證。

(2)初始化BeanFactory仔引,并進(jìn)行XML文件讀热硬帧:之前提到過(guò)ClassPathXmlApplicationContext包含著B(niǎo)eanFactory所提供的一切特征,那么在這一步驟中將會(huì)復(fù)用BeanFactory中的配置文件讀取解析及其他功能咖耘,這一步之后翘簇,ClassPathXmlApplicationContext實(shí)際上就已經(jīng)包含了BeanFactory所提供的功能,也就是可以進(jìn)行Bean的提取等基礎(chǔ)操作了儿倒。

(3)對(duì)BeanFatory進(jìn)行各種功能填充:@Qualifer與@Autowired應(yīng)該是大家非常熟悉的注解版保,這兩個(gè)注解正是在這一步驟中增加的支持

(4)子類覆蓋方法做額外的處理:Spring之所以強(qiáng)大,為世人所推崇夫否,除了它功能上為大家提供了便利外朴爬,還有一方面就是它的完美架構(gòu)悍引,開(kāi)放式的架構(gòu)讓使用它的程序員很容易根據(jù)業(yè)務(wù)需要擴(kuò)展已經(jīng)存在的功能枉侧。這種開(kāi)放式的設(shè)計(jì)在Spring中隨處可見(jiàn)钳榨,例如在本例中就提供了一個(gè)空的函數(shù)實(shí)現(xiàn)postProcessBeanFactory來(lái)方便程序員在業(yè)務(wù)上做進(jìn)一步擴(kuò)展。

(5)激活各種BeanFatory處理器

(6)注冊(cè)攔截bean創(chuàng)建的bean處理器微谓,這里只是注冊(cè)森篷,真正的調(diào)用是在getBean的時(shí)候

(7)為上下文初始化Message源输钩,即對(duì)不同語(yǔ)言的消息體進(jìn)行國(guó)際化處理

(8)初始化應(yīng)用消息廣播器,并放入"applicationEventMulticaster"bean中

(9)留給子類來(lái)初始化其他的bean

(10)在所有注冊(cè)的bean中查找listener bean疾宏,注冊(cè)到消息廣播器中

(11)初始化剩下的單實(shí)例(非惰性的)

(12)完成刷新過(guò)程张足,通知聲明周期處理器lifecycleProcessor刷新過(guò)程,同時(shí)發(fā)出ContextRefreshEven通知?jiǎng)e人

環(huán)境準(zhǔn)備

protected void prepareRefresh() {
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);

    if (logger.isInfoEnabled()) {
        logger.info("Refreshing " + this);
    }

    //留給子類覆蓋
    initPropertySources();

    //驗(yàn)證需要的屬性文件是否都已經(jīng)放入環(huán)境中
    getEnvironment().validateRequiredProperties();

    // Allow for the collection of early ApplicationEvents,
    // to be published once the multicaster is available...
    this.earlyApplicationEvents = new LinkedHashSet<>();
}

有人說(shuō)其實(shí)這個(gè)函數(shù)沒(méi)什么用坎藐,因?yàn)樽詈髢删浯a才是最為關(guān)鍵的,但是卻沒(méi)有什么邏輯處理哼绑,initPropertySources是空的岩馍,沒(méi)有任何邏輯,而getEnvironment().validateRequiredProperties也因?yàn)闆](méi)有需要驗(yàn)證的屬性而沒(méi)有做任何處理抖韩。其實(shí)這都是因?yàn)闆](méi)有徹底理解才會(huì)這么說(shuō)蛀恩,這個(gè)函數(shù)用好了作用還是很大的。那么茂浮,該怎么用呢双谆?我們先探索下各個(gè)函數(shù)的作用。

(1)initPropertySources:正符合Spring的開(kāi)放式結(jié)構(gòu)設(shè)計(jì)席揽,給用戶最大擴(kuò)展Spring的能力顽馋。用戶可以根據(jù)自身的需要重寫(xiě)initPropertySources方法,并在方法中進(jìn)行個(gè)性化的屬性處理及設(shè)置幌羞。

(2)validateRequiredProperties:則是對(duì)屬性進(jìn)行驗(yàn)證寸谜,那么如何驗(yàn)證呢?我們舉個(gè)融合兩句代碼的小例子來(lái)幫助大家理解属桦。

假如現(xiàn)在有這樣一個(gè)需求熊痴,工程在運(yùn)行過(guò)程中用到的摸個(gè)設(shè)置(例如VAR)是從系統(tǒng)環(huán)境變量中取得的,而如果用戶沒(méi)有在系統(tǒng)環(huán)境變量中配置這個(gè)參數(shù)聂宾,那么工程可能不會(huì)工作果善,這一要求可能會(huì)有各種各樣的解決辦法,當(dāng)然系谐,在Spring中可以這樣做巾陕,你可以直接修改Spring的源碼,例如修改ClassPathXmlApplicationContext蔚鸥。不過(guò)最好的辦法還是對(duì)源碼進(jìn)行擴(kuò)展惜论,我們可以自定義類:

public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{
    public MyClassPathXmlApplicationContext(String... configLocation){
        super(configLocation);
    }
 
    protected void initPropertySources(){
        getEnvironment().setRequiredProperties("VAR");
    }
}

我們自定義了繼承自ClassPathXmlApplicationContext的MyClassPathXmlApplicationContext,并重寫(xiě)了initPropertySources方法止喷,在方法中添加了我們的個(gè)性化需求馆类,那么在驗(yàn)證的時(shí)候也就是程序走到getEnvironment().validateRequiredProperties()代碼的時(shí)候,如果系統(tǒng)并沒(méi)有檢測(cè)到對(duì)應(yīng)VAR的環(huán)境變量弹谁,那么將拋出異常乾巧。當(dāng)然我們還需要在使用的時(shí)候替換掉原有的ClassPathXmlApplicationContext:

public static void main(String[] args){
    ApplicationContext bf = new ClassPathXmlApplicationContext("test/customag/test.xml");
    User user = (User)bf.getBean("user");
}

加載BeanFactory

obtainFreshBeanFactory方法從字面理解是獲取BeanFactory句喜。之前說(shuō)過(guò),ApplicationContext是對(duì)BeanFactory在功能上的擴(kuò)展沟于,不但包含了BeanFactory的全部功能更在其基礎(chǔ)上添加了大量的擴(kuò)展應(yīng)用咳胃,那么obtainFreshBeanFactory正是實(shí)現(xiàn)BeanFactory的地方,也就是經(jīng)過(guò)這個(gè)函數(shù)后旷太,ApplicationContext正式擁有了BeanFactory的全部功能展懈。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}

protected final void refreshBeanFactory() throws BeansException {
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        //創(chuàng)建DefualtListableBeanFactory
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        //為了序列化指定id,如果需要的話供璧,讓這個(gè)BeanFactory從id反序列化到BeanFactory對(duì)象
        beanFactory.setSerializationId(getId());
        //定制beanFactory相關(guān)屬性存崖,包括是否允許覆蓋同名稱的不同定義的對(duì)象以及
        //設(shè)置@Autowired和@Qualifier注解解析器QualifierAnnotationAutowiredCandidateResolver
        customizeBeanFactory(beanFactory);
        //初始化DocumentReader,并進(jìn)行XML文件讀取及解析
        loadBeanDefinitions(beanFactory);
        synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
        }
    }
    catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

我們?cè)敿?xì)分析上面的每個(gè)步驟

(1)創(chuàng)建DefaultListableBeanFactory睡毒。

在介紹BeanFactory的時(shí)候来惧,不知道大家有沒(méi)有印象,聲明方式為:BeanFactory bf = new XmlBeanFactory("test.xml")演顾,其中的XmlBeanFactory繼承自DefaultListableBeanFactory,并提供了XmlBeanDefinitionReader類型的reader屬性供搀,也就是說(shuō)DefaultListableBeanFactory是容器的基礎(chǔ)。必須首先實(shí)例化钠至,那么在這里就是實(shí)例化DefaultListableBeanFactory的步驟葛虐。

(2)指定序列化ID

(3)定制BeanFactory

(4)加載BeanDefinition

(5)使用全局變量BeanFactory類實(shí)例

因?yàn)镈efaultListableBeanFactory類型的變量beanFactory是函數(shù)內(nèi)的局部變量,所以要使用全局變量來(lái)記錄結(jié)果棕洋。

定制BeanFactory

這里已經(jīng)開(kāi)始了對(duì)BeanFactory功能的擴(kuò)展挡闰,在基本容器的基礎(chǔ)上,增加了是否允許覆蓋是否允許循環(huán)依賴掰盘。

    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
        //如果屬性allowBeanDefinitionOverriding不為空摄悯,設(shè)置給beanFactory對(duì)象相應(yīng)屬性,
        //此屬性含義:是否允許覆蓋同名稱的不同定義的對(duì)象
        if (this.allowBeanDefinitionOverriding != null) {
            beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        //如果屬性allowCircularReferences不為空愧捕,設(shè)置給beanFactory對(duì)象相應(yīng)屬性奢驯,
        //此屬性含義:是否允許bean之間循環(huán)依賴
        if (this.allowCircularReferences != null) {
            beanFactory.setAllowCircularReferences(this.allowCircularReferences);
        }
    }

對(duì)于允許覆蓋和允許循環(huán)依賴的設(shè)置這里只是判斷了是否為空,如果不為空要進(jìn)行設(shè)置次绘,但是并沒(méi)有看到在哪里進(jìn)行設(shè)置瘪阁,究竟這個(gè)設(shè)置是在哪里進(jìn)行設(shè)置的呢?還是那句話邮偎,使用子類覆蓋方法管跺,例如:

public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{
    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory){
        super.setAllowBeanDefinitionOverriding(false);
        super.setAllowCircularReferences(false);
        super.customizeBeanFactory(this.beanFactory);
    }
}

設(shè)置完后相信大家已經(jīng)對(duì)于這兩個(gè)屬性的使用有所了解,或者可以看前面的文章進(jìn)行了解禾进。

加載BeanDefinition

在第一步中提到了將ClassPathXmlApplicationContext與XmlBeanFactory創(chuàng)建的對(duì)比豁跑,在實(shí)現(xiàn)配置文件的加載功能中除了我們?cè)诘谝徊揭呀?jīng)初始化的DefaultListableBeanFactory外,還需要XmlBeanDefinitionReader來(lái)讀取XML泻云,那么在這個(gè)步驟中首先要做的就是初始化XmlBeanDefinitionReader艇拍。

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        //為給定的beanFactory創(chuàng)建一個(gè)XmlBeanDefinitionReader
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
 
        //對(duì)beanDefinitionReader進(jìn)行環(huán)境變量的設(shè)置
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
 
        //對(duì)BeanDefinitionReader進(jìn)行設(shè)置狐蜕,可以覆蓋
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }

在初始化了DefaultListableBeanFactory和XmlBeanDefinitionReader后就可以配置文件的讀取了。

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }

使用XmlBeanDefinitionReader的loadBeanDefinitions方法進(jìn)行配置文件的加載機(jī)制注冊(cè)卸夕,后面的代碼就又回到了前兩篇文章中所分析的流程了层释,所以這里就不再贅述了。同時(shí)快集,經(jīng)過(guò)此步驟之后贡羔,XmlBeanDefinitionReader所讀取的BeanDefinitionHolder就都注冊(cè)到了DefaultListableBeanFactory中了,此時(shí)的DefaultListableBeanFactory已經(jīng)包含了所有解析好的配置了碍讨。

功能擴(kuò)展

進(jìn)入函數(shù)prepareBeanFactory之前治力,Spring已經(jīng)完成了對(duì)配置的解析,而ApplicationContext在功能上的擴(kuò)展也由此展開(kāi)

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    //設(shè)置beanFactory的classLoader為當(dāng)前context的classLoader
    beanFactory.setBeanClassLoader(getClassLoader());
    //設(shè)置beanFactory的表達(dá)式語(yǔ)言處理器勃黍,Spring3增加了表達(dá)式語(yǔ)言的支持,
    //默認(rèn)可以使用#{bean.xxx}的形式來(lái)調(diào)用相關(guān)屬性值
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    //為beanFactory增加一個(gè)默認(rèn)的propertyEditor晕讲,這個(gè)主要是對(duì)bean的屬性等設(shè)置管理的一個(gè)工具
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    //添加BeanPostProcessor
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    //設(shè)置幾個(gè)忽略自動(dòng)裝配的接口
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    //設(shè)置幾個(gè)自動(dòng)裝配的特殊規(guī)則
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    //添加一個(gè)ApplicationListenerDetector類型的BeanPostProcessor
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    //增加對(duì)AspectJ的支持
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // Set a temporary ClassLoader for type matching.
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    //添加默認(rèn)的系統(tǒng)環(huán)境bean
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
}

上面函數(shù)中主要進(jìn)行了幾個(gè)方面的擴(kuò)展覆获。

1.增加對(duì)SpEL語(yǔ)言的支持

2.增加對(duì)屬性編輯器的支持

3.增加對(duì)一些內(nèi)置類,比如EnvironmentAware瓢省、MessageSourceAware的信息注入弄息。

4.設(shè)置了依賴功能可忽略的接口。

5.注冊(cè)一些固定依賴的屬性

6.增加AspectJ的支持

7.將相關(guān)環(huán)境變量及屬性注冊(cè)以單利模式注冊(cè)勤婚。

下面我們來(lái)一一的看一下每個(gè)步驟的流程

增加SPEL語(yǔ)言的支持

Spring表達(dá)式語(yǔ)言全稱為"Spring Expression Language"摹量,縮寫(xiě)為"SpEL",類似于Struts2x中使用的OGNL表達(dá)式語(yǔ)言馒胆,能在運(yùn)行時(shí)構(gòu)建復(fù)雜表達(dá)式缨称、存取對(duì)象圖屬性、對(duì)象方法調(diào)用等祝迂,并且能與Spring功能完美整合睦尽,比如能用來(lái)配置bean定義。SpEL是單獨(dú)模塊型雳,只依賴與core模塊当凡,不依賴與其他模塊,可以單獨(dú)使用纠俭。

SpEL使用#{...}作為定界符沿量,所有在大括號(hào)中的字符都將被認(rèn)為是SpEL,使用格式如下:

<bean id="saxophone" value="com.xxx.xxx.Xxxx" />
<bean>
<property name="instument" value="#{saxophone}"/>
</bean>
相當(dāng)于:

<bean id="saxophone" value="com.xxx.xxx.Xxxx" />
<bean>
<property name="instrument" ref="saxophone">
</bean>
當(dāng)然冤荆,上面只是列舉了其中最簡(jiǎn)單的使用方式朴则,SpEL功能非常強(qiáng)大,使用好可以大大提高開(kāi)發(fā)效率匙赞,這里只是為了幫助我們理解源碼佛掖,所以不做過(guò)多的研究妖碉。
在源碼中通過(guò)代碼beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver())注冊(cè)語(yǔ)言解析器,就可以對(duì)SpEL進(jìn)行解析了芥被,那么在注冊(cè)解析器后Spring又是在什么時(shí)候調(diào)用這個(gè)解析器進(jìn)行解析呢欧宜?

之前我們說(shuō)過(guò)Spring在bean進(jìn)行初始化的時(shí)候會(huì)有屬性填充這一步,而在這步中Spring會(huì)調(diào)用AbstractAutowireCapableBeanFactory類applyPropertyValues函數(shù)來(lái)完成功能拴魄。就在這個(gè)函數(shù)中冗茸,會(huì)通過(guò)構(gòu)造BeanDefinitionValueResolver類型實(shí)例valueResolver來(lái)進(jìn)行屬性值的解析。同時(shí)匹中,也是在這個(gè)步驟中一般通過(guò)AbstractBeanFactory中的evaluateBeanDefinitionString方法去完成SpEL解析夏漱。

    protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {
        if (this.beanExpressionResolver == null) {
            return value;
        }
 
        Scope scope = null;
        if (beanDefinition != null) {
            String scopeName = beanDefinition.getScope();
            if (scopeName != null) {
                scope = getRegisteredScope(scopeName);
            }
        }
        return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
    }

當(dāng)調(diào)用這個(gè)方法時(shí)會(huì)判斷是否存在語(yǔ)言解析器,如果存在則調(diào)用語(yǔ)言解析器的方法進(jìn)行解析顶捷,解析的過(guò)程是在Spring的expression的包內(nèi)挂绰,這里不做過(guò)多解釋。我們通過(guò)查看對(duì)evaluateBeanDefinitionString方法的調(diào)用層次可以看出服赎,應(yīng)用語(yǔ)言解析器的調(diào)用主要是在解析依賴注入bean的時(shí)候葵蒂,以及在完成bean的初始化和屬性獲取后進(jìn)行屬性填充的時(shí)候。

增加屬性注冊(cè)編輯器

在Spring依賴注入的時(shí)候可以把普通屬性注入進(jìn)來(lái)重虑,但是像Date類型就無(wú)法被識(shí)別践付,例如:

public class UserManager{
    private Date dataValue;
 
    public Date getDataValue(){
        return dataValue;
    }
 
    public void setDataValue(Date dataValue){
        this.dataValue = dataValue;
    }
 
    public String toString(){
        return "dataValue = " + dataValue;
    }
}

上面代碼中,需要對(duì)日期型屬性進(jìn)行注入:

<bean id="userManager" class="com.test.UserManager">
    <property name="dataValue">
        <value>2018-06-30</value>
    </property>
</bean>

測(cè)試代碼:

@Test 
public void testDate(){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
    UserManager userManager = (UserManager)ctx.getBean("userManager");
    System.out.println(userManager);
}

如果直接這樣使用缺厉,程序則會(huì)報(bào)異常永高,類型轉(zhuǎn)換不成功。因?yàn)樵赨serManager中的dataValue屬性是Date類型的提针,而在XML中配置的則是String類型的命爬,所以會(huì)報(bào)異常。

Spring針對(duì)這個(gè)問(wèn)題提供了兩種解決方法:

1.使用自定義屬性編輯器

使用自定義屬性編輯器关贵,通過(guò)繼承PropertyEditorSupport遇骑,重寫(xiě)setAsText方法,具體步驟如下:

(1)編寫(xiě)自定義的屬性編輯器:

public class DatePropertyEditor extends PropertyEditorSupport{
    private String format = "yyyy-MM-dd";
    public void setFormat(String format){
        this.format = format;
    }

    public void setAsText(String arg0) throws IllegalArgumentException{
        System.out.println("arg0: " + arg0);
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try{
            Date d = sdf.parse(arg0);
            this.setValue(d);
        }catch(ParseException e){
            e.printStackTrace();
        }
    }
}

(2)將自定義屬性編輯器注冊(cè)到Spring中:

<bean class="org.Springframework.beans.factory.config.CustomEditorConfigurer">
   <property name="customEditors">
       <map>
           <entry key="java.util.Date">
               <bean class="com.test.DatePropertyEditor">
                   <property name="format" value="yyyy-MM-dd"/>
               </bean>
           </entry>
       </map>
   </property>
</bean>

在配置文件中引入類型為org.Springframework.beans.factory.config.CustomEditorConfigurer的bean揖曾,并在屬性customEditors中加入自定義的屬性編輯器落萎,其中key為屬性編輯器所對(duì)應(yīng)的類型。通過(guò)這樣的配置炭剪,當(dāng)Spring注入bean的屬性時(shí)一旦遇到了java.util.Date類型的屬性會(huì)自動(dòng)調(diào)用自定義的DatePropertyEditor解析器進(jìn)行解析练链,并用解析結(jié)果代替配置屬性進(jìn)行注入。

2.注冊(cè)Spring自帶的屬性編輯器CustomDateEditor

通過(guò)注冊(cè)Spring自帶的屬性編輯器CustomDateEditor奴拦,具體步驟如下:

(1)定義屬性編輯器

public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar{
   public void registerCustomEditors(PropertyEditorRegistry registry){
       registry.registerCustomEditors(Date.class, new CustomDateEditor(
           new SimpleDateFormat("yyyy-MM-dd"), true)
       );
   }
}

(2)注冊(cè)到Spring中

<bean class="org.Springframework.bean.factory.config.CustomEditorConfigurer">
   <property name="propertyEditorRegistrars">
       <list>
           <bean class="com.test.DatePropertyEditorRegistrar" />
       </list>
   </property>
</bean>

通過(guò)在配置文件中將自定義的DatePropertyEditorRegistrar注冊(cè)進(jìn)入org.Springframework.beans.factory.config. CustomEditorConfigurer的propertyEditorRegistrars屬性中媒鼓,可以具有與方法1同樣的效果。

我們了解了自定義屬性編輯器的使用,但是绿鸣,這似乎與本篇文章中圍繞的核心代碼beanFactory.addPropertyEditorRegistrar( newResourceEditorRegistrar(this, getEnvironment()))并無(wú)聯(lián)系疚沐,因?yàn)樵谧?cè)自定義屬性編輯器的時(shí)候使用的是PropertyEditor Registry的registerCustomEditor方法,我們不妨深入探索一下ResourceEditorRegistrar的內(nèi)部實(shí)現(xiàn)潮模,在ResourceEditorRegistrar中亮蛔,我們最關(guān)心的方法是registerCustomEditors。

   public void registerCustomEditors(PropertyEditorRegistry registry) {
       ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
       doRegisterEditor(registry, Resource.class, baseEditor);
       doRegisterEditor(registry, ContextResource.class, baseEditor);
       doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
       doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
       doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
       doRegisterEditor(registry, Path.class, new PathEditor(baseEditor));
       doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
       doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));

       ClassLoader classLoader = this.resourceLoader.getClassLoader();
       doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
       doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
       doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));

       if (this.resourceLoader instanceof ResourcePatternResolver) {
           doRegisterEditor(registry, Resource[].class,
                   new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver));
       }
   }

   private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
       if (registry instanceof PropertyEditorRegistrySupport) {
           ((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);
       }
       else {
           registry.registerCustomEditor(requiredType, editor);
       }
   }

在doRegisterEditor函數(shù)中擎厢,可以看到在之前提到的自定義屬性中使用的關(guān)鍵代碼:registry.registerCustomEditor(requiredType, editor)究流,回過(guò)頭來(lái)看ResourceEditorRegistrar類的registerCustomEditors方法的核心功能,其實(shí)無(wú)非是注冊(cè)了一系列的常用類型的屬性編輯器动遭,例如芬探,代碼doRegisterEditor(registry, Class.class, new ClassEditor(classLoader))實(shí)現(xiàn)的功能就是注冊(cè)Class類對(duì)應(yīng)的屬性編輯器。那么注冊(cè)后厘惦,一旦某個(gè)實(shí)體bean中存在一些Class類型的屬性偷仿,那么Spring會(huì)調(diào)用ClassEditor將配置中定義的String類型轉(zhuǎn)換為Class類型并進(jìn)行賦值。

分析到這里宵蕉,我們不禁有個(gè)疑問(wèn)炎疆,雖說(shuō)ResourceEditorRegistrar類的registerCustomEditors方法實(shí)現(xiàn)了批量注冊(cè)的功能,但是bean Factroy.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()))僅僅是注冊(cè)了ResourceEditor Registrar實(shí)例国裳,卻并沒(méi)有調(diào)用ResourceEditorRegistrar的registerCustomEditors方法進(jìn)行注冊(cè),那么到底是什么時(shí)候進(jìn)行注冊(cè)的呢全跨,進(jìn)一步查看ResourceEditorRegistrar的registerCustomEditors方法的調(diào)用層次結(jié)構(gòu)缝左,如圖:


image.png

發(fā)現(xiàn)在AbstractBeanFactory中的registerCustomEditors方法中被調(diào)用過(guò),繼續(xù)查看AbstractBeanFactory中的register CustomEditors方法的調(diào)用層次結(jié)構(gòu)浓若,如圖:

image.png

其中我們看到了一個(gè)熟悉的方法渺杉,就是initBeanWrapper方法,這是在bean初始化時(shí)使用的一個(gè)方法挪钓,之前已經(jīng)使用過(guò)大量的篇幅進(jìn)行講解是越,主要是將BeanDefinition轉(zhuǎn)換為BeanWrapper后用于對(duì)屬性的填充。至此碌上,邏輯已經(jīng)明了倚评,在bean的初始化后悔調(diào)用ResourceEditorRegistrar的registerCustomEditors方法進(jìn)行批量的通用屬性編輯器注冊(cè)。注冊(cè)后馏予,在屬性填充的環(huán)節(jié)便可以直接讓Spring使用這些編輯器進(jìn)行屬性的解析了天梧。

既然提到了BeanWrapper,這里有必要強(qiáng)調(diào)下霞丧,Spring用于封裝bean的是BeanWrapper類型呢岗,而它又間接繼承了Property EditorRegistry類型,也就是我們之間反復(fù)看到的方法參數(shù)PropertyEditorRegistry,其實(shí)大部分情況下都是BeanWrapper后豫,對(duì)于BeanWrapper在Spring中默認(rèn)實(shí)現(xiàn)是BeanWrapperImpl悉尾,而B(niǎo)eanWrapperImpl除了實(shí)現(xiàn)BeanWrapper接口外還繼承了PropertyEditorRegistrySupport,在PropertyEditorRegistrySupport中有這樣一個(gè)方法:

    private void createDefaultEditors() {
        this.defaultEditors = new HashMap<>(64);
 
        // Simple editors, without parameterization capabilities.
        // The JDK does not contain a default editor for any of these target types.
        this.defaultEditors.put(Charset.class, new CharsetEditor());
        this.defaultEditors.put(Class.class, new ClassEditor());
        this.defaultEditors.put(Class[].class, new ClassArrayEditor());
        this.defaultEditors.put(Currency.class, new CurrencyEditor());
        this.defaultEditors.put(File.class, new FileEditor());
        this.defaultEditors.put(InputStream.class, new InputStreamEditor());
        this.defaultEditors.put(InputSource.class, new InputSourceEditor());
        this.defaultEditors.put(Locale.class, new LocaleEditor());
        this.defaultEditors.put(Path.class, new PathEditor());
        this.defaultEditors.put(Pattern.class, new PatternEditor());
        this.defaultEditors.put(Properties.class, new PropertiesEditor());
        this.defaultEditors.put(Reader.class, new ReaderEditor());
        this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());
        this.defaultEditors.put(TimeZone.class, new TimeZoneEditor());
        this.defaultEditors.put(URI.class, new URIEditor());
        this.defaultEditors.put(URL.class, new URLEditor());
        this.defaultEditors.put(UUID.class, new UUIDEditor());
        this.defaultEditors.put(ZoneId.class, new ZoneIdEditor());
 
        // Default instances of collection editors.
        // Can be overridden by registering custom instances of those as custom editors.
        this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
        this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
        this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
        this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
        this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));
 
        // Default editors for primitive arrays.
        this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
        this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());
 
        // The JDK does not contain a default editor for char!
        this.defaultEditors.put(char.class, new CharacterEditor(false));
        this.defaultEditors.put(Character.class, new CharacterEditor(true));
 
        // Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor.
        this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false));
        this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));
 
        // The JDK does not contain default editors for number wrapper types!
        // Override JDK primitive number editors with our own CustomNumberEditor.
        this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false));
        this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
        this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false));
        this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
        this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false));
        this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
        this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false));
        this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
        this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false));
        this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
        this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false));
        this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));
        this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
        this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));
 
        // Only register config value editors if explicitly requested.
        if (this.configValueEditorsActive) {
            StringArrayPropertyEditor sae = new StringArrayPropertyEditor();
            this.defaultEditors.put(String[].class, sae);
            this.defaultEditors.put(short[].class, sae);
            this.defaultEditors.put(int[].class, sae);
            this.defaultEditors.put(long[].class, sae);
        }
    }

具體的調(diào)用方法我們就不去深究了挫酿,但是至少通過(guò)這個(gè)方法我們已經(jīng)知道了在Spring中定義了上面一系列常用的屬性編輯器使我們可以方便地進(jìn)行配置构眯。如果我們定義的bean的某個(gè)屬性的類型不在上面的常用配置中的話,才需要我們進(jìn)行個(gè)性化屬性編輯器的注冊(cè)饭豹。

3.添加ApplicationContextAwareProcessor處理器

了解了屬性編輯器的使用后鸵赖,接下來(lái)我們繼續(xù)回到AbstractApplicationContext的prepareBeanFactory方法的主線來(lái)進(jìn)行函數(shù)追蹤。對(duì)于beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))其實(shí)主要目的就是注冊(cè)BeanPost Processor拄衰,而真正的邏輯還是在ApplicationContextAwareProcessor中它褪。

ApplicationContextAwareProcessor實(shí)現(xiàn)了BeanPostProcessor接口,我們回顧一下之前的內(nèi)容翘悉,在bean實(shí)例化的時(shí)候茫打,也就是Spring激活bean的init-method的前后,會(huì)調(diào)用BeanPostProcessor的postProcessorBeforeInitialization方法和postProcessorAfterInitialization方法妖混,同樣老赤,對(duì)于ApplicationContextAwareProcessor我們也關(guān)心這兩個(gè)方法。

對(duì)于postProcessAfterInitialization方法制市,在ApplicationContextAwareProcessor中并沒(méi)有做過(guò)多邏輯處理

    public Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }

那么我們重點(diǎn)看一下postProcessBeforeInitialization方法

    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        AccessControlContext acc = null;
 
        if (System.getSecurityManager() != null &&
                (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }
 
        if (acc != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareInterfaces(bean);
                return null;
            }, acc);
        }
        else {
            invokeAwareInterfaces(bean);
        }
 
        return bean;
    }
 
    private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof EnvironmentAware) {
                ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
            }
            if (bean instanceof EmbeddedValueResolverAware) {
                ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
            }
            if (bean instanceof ResourceLoaderAware) {
                ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
            }
            if (bean instanceof ApplicationEventPublisherAware) {
                ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
            }
            if (bean instanceof MessageSourceAware) {
                ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
            }
            if (bean instanceof ApplicationContextAware) {
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            }
        }
    }

postProcessBeforeInitialization方法中調(diào)用了invokeAwareInterfaces抬旺。從invokeAwareInterfaces方法中,我們或許已經(jīng)或多或少了解了Spring的用意祥楣,實(shí)現(xiàn)這些Aware接口的bean在被初始化之后开财,可以取得一些對(duì)應(yīng)的資源。

4.設(shè)置忽略依賴

當(dāng)Spring將ApplicationContextAwareProcessor注冊(cè)后误褪,那么在invokeAwareInterfaces方法中間接調(diào)用的Aware類已經(jīng)不是普通的bean了责鳍,如ResourceLoaderAware、ApplicationEventPublisherAware等兽间,那么當(dāng)然需要再Spring做bean的依賴注入的時(shí)候忽略它們历葛。而ignoreDependencyInterfaces的作用正是在此。

        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

5.注冊(cè)依賴

Spring中有忽略依賴的功能嘀略,當(dāng)然也必不可少的會(huì)有注冊(cè)依賴的功能恤溶。

        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

當(dāng)注冊(cè)了依賴解析后,例如當(dāng)注冊(cè)了對(duì)BeanFactory.class的解析依賴后屎鳍,當(dāng)bean的屬性注入的時(shí)候宏娄,一旦檢測(cè)到屬性為BeanFactory類型便會(huì)將beanFactory實(shí)例注入進(jìn)去

BeanFactory的后處理

BeanFactory作為Spring中容器功能的基礎(chǔ),用于存放所有已經(jīng)加載的bean逮壁,為了保證程序上的高可擴(kuò)展性孵坚,Spring針對(duì)BeanFactory做了大量的擴(kuò)展粮宛,比如我們熟知的PostProcessor等都是在這里實(shí)現(xiàn)的。

1.激活注冊(cè)的BeanFactoryPostProcessor

正式開(kāi)始介紹之前我么你先了解下BeanFactoryPostProcessor的用法卖宠。

BeanFactoryPostProcessor接口和BeanPostProcessor類似巍杈,可以對(duì)bean的定義(配置元數(shù)據(jù))進(jìn)行處理,也就是說(shuō)扛伍,SpringIoC容器允許BeanFactoryPostProcessor在容器實(shí)際實(shí)例化任何其他的bean之前讀取配置元數(shù)據(jù)筷畦,并有可能修改它。如果你愿意刺洒,你可以配置多個(gè)BeanFactoryPostProcessor鳖宾。你還可以通過(guò)設(shè)置"order"屬性來(lái)控制BeanFactoryPostProcessor的執(zhí)行次序(僅當(dāng)BeanFactoryPostProcessor實(shí)現(xiàn)了Ordered接口)。具體請(qǐng)參考BeanFactoryPostProcessor和Ordered接口的JavaDoc以獲取更詳細(xì)的信息逆航。

如果你想改變實(shí)際的bean實(shí)例(例如從配置元數(shù)據(jù)創(chuàng)建的對(duì)象)鼎文,那么你最好使用BeanPostProcessor。同樣的因俐,BeanFactoryPost Processor的作用域范圍是容器級(jí)的拇惋。它只和你所使用的容器有關(guān)。如果你在容器中定義一個(gè)BeanFactoryPostProcessor抹剩,它僅僅對(duì)此容器中的bean進(jìn)行后置處理撑帖。BeanFactoryPostProcessor不會(huì)對(duì)定義在另一個(gè)容器中的bean進(jìn)行后置處理。即使這兩個(gè)容器在同一個(gè)層次上澳眷。在Spring中存在對(duì)于BeanFactoryPostProcessor的典型應(yīng)用胡嘿,比如PropertyPlaceholderConfigurer。

有時(shí)候钳踊,閱讀Spring的Bean描述文件時(shí)灶平,我們也許會(huì)遇到類似如下的一些配置:

<bean id="message" class="distConfig.HelloMessage">
    <property name="mes">
        <value>${bean.message}</value>
    </property>
</bean>

其中竟然出現(xiàn)了變量引用:${bean.message}。這就是Spring的分散配置箍土,可以在另外的配置文件中為bean.message指定值。如在bean.property配置如下定義:

bean.message=Hi,can you find me?
當(dāng)訪問(wèn)名為message的bean時(shí)罐监,mes屬性就會(huì)被設(shè)置為“Hi,can you find me?”吴藻,但Spring框架是怎么知道存在這樣的配置文件的呢?這就要靠PropertyPlaceholderConfigurer這個(gè)類的bean:

<bean id="mesHandler" class="org.Springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>config/bean.properties</value>
        </list>
    </property>
</bean>

在這個(gè)bean中指定了配置文件為config/bean.properties弓柱。到這里似乎找到了問(wèn)題的答案了沟堡,但是其實(shí)還有個(gè)問(wèn)題。這個(gè)"mesHandler"只不過(guò)是Spring框架管理的一個(gè)bean矢空,并沒(méi)有被別的bean或者對(duì)象引用航罗,Spring的beanFactory是怎么知道要從這個(gè)bean中獲取配置信息的呢?

查看層級(jí)結(jié)構(gòu)可以看出PropertyPlaceholderConfigurer這個(gè)類間接繼承了BeanFactoryPostProcessor接口屁药。這是一個(gè)特別的接口粥血,當(dāng)Spring加載任何實(shí)現(xiàn)了這個(gè)接口的bean的配置時(shí),都會(huì)在bean工廠載入所有bean的配置之后執(zhí)行PostProcessorBeanFactory方法。在PropertyPlaceholderConfigurer類中實(shí)現(xiàn)了postProcessorBeanFactory方法复亏。在mergePorperties趾娃、convertProperties、processProperties這3個(gè)方法缔御,分別得到配置抬闷,將得打的配置轉(zhuǎn)換為合適的類型,最后將配置內(nèi)容告知BeanFactory耕突。

正是通過(guò)實(shí)現(xiàn)BeanFactoryPostProcessor接口笤成,BeanFactory會(huì)在實(shí)例化任何bean之前獲得配置信息,從而能夠正確解析bean描述文件中的變量引用眷茁。

下面我們自定義一個(gè)實(shí)現(xiàn)了BeanFactoryPostProcessor接口的類來(lái)體驗(yàn)一下整個(gè)過(guò)程啼器。我們通過(guò)實(shí)現(xiàn)BeanFactoryPostProcessor接口备蚓,來(lái)去除潛在的“流氓”屬性值,例如bean定義下留下bollocks這樣的字眼:

<bean id="bfpp" class="com.Spring.test.ObscenityRemovingBeanFactoryPostProcessor">
    <property name="obscenties">
        <set>
            <value>bollocks</value>
            <value>winky<value>
            <value>bum<value>
            <value>Microsoft<value>
        </set>
    </property>
</bean>
 
<bean id="simpleBean" class="com.Spring.test.SimplePostProcessor">
    <property name="connectionString" value="bollocks" />
    <property name="password" value="imaginecup" />
    <property name="username" value="Microsoft" />
</bean> 
public class ObscenityRemovingBeanFactoryPostProcessor implements BeanFactoryPostProcessor{
    private Set<String> obscenties;
    public ObscenityRemovingBeanFactoryPostProcessor(){
        this.obscenties = new HashSet<String>();
    }
 
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException{
        String[] beanNames = beanFactory.getBeanDefinitionNames();
        for(String beanName:beanNames){
            BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
            StringValueResolver valueResolver = new StringValueResolver(){
                public String resolveStringValue(String strVal){
                    if(isObscene(StrVal)) return "******";
                    return strVal;
                }
            }
            BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
            visitor.visitBeanDefinition(bd);
        }
    }
 
    public boolean isObscene(Object value){
        String potentialObscenity = value.toString().toUpperCase();
        return this.obscenties.contains(potentialObscenity);
    }
 
    public void setObscenties(Set<String> obscenties){
        this.obscenties.clear();
        for(String obscenty : obscenties){
            this.obscenties.add(obscenty.toUpperCase());
        }
    }
}

執(zhí)行類

public class PropertyConfigurerDemo{
    public static void main(String[] args){
        ConfigurableListableBeanFactory bf = new XmlBeanFactory(new 
            ClassPathResource("/META-INF/BeanFactory.xml"));
        BeanFactoryPostProcessor bfpp = (BeanFactoryPostProcessor)bf.getBean("bfpp");
        bfpp.postProcessBeanFactory(bf);
        System.out.println(bf.getBean("simpleBean"));
    }
}

輸出結(jié)果

SimplePostProcessor{connectionString=******,username=******,password=imaginecup}

通過(guò)ObscenityRemovingBeanFactoryPostProcessor,Spring很好的實(shí)現(xiàn)了屏蔽掉obscenties定義的不應(yīng)該展示的屬性鸡捐。

了解了BeanFactoryPostProcessor的用法后便可以深入研究BeanFactoryPostProcessor的調(diào)用過(guò)程了。

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    //調(diào)用 PostProcessorRegistrationDelegate 的 invokeBeanFactoryPostProcessors方法
        if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    }

繼續(xù)調(diào)用PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法吗伤,我們繼續(xù)跟蹤代碼:

    public static void invokeBeanFactoryPostProcessors(
            ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
 
        // Invoke BeanDefinitionRegistryPostProcessors first, if any.
        Set<String> processedBeans = new HashSet<>();
 
        //對(duì) BeanDefinitionRegistry 類型的處理
        if (beanFactory instanceof BeanDefinitionRegistry) {
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();
            List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();
 
            for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
                if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                    BeanDefinitionRegistryPostProcessor registryProcessor =
                            (BeanDefinitionRegistryPostProcessor) postProcessor;
                    //對(duì)于 BeanDefinitionRegistryPostProcessor 類型珠移,在 BeanFactoryPostProcessor的
                    //基礎(chǔ)上還有自己定義的方法,需要先調(diào)用
                    registryProcessor.postProcessBeanDefinitionRegistry(registry);
                    registryProcessors.add(registryProcessor);
                }
                else {
                    //記錄常規(guī) BeanFactoryPostProcessor
                    regularPostProcessors.add(postProcessor);
                }
            }
 
            // Do not initialize FactoryBeans here: We need to leave all regular beans
            // uninitialized to let the bean factory post-processors apply to them!
            // Separate between BeanDefinitionRegistryPostProcessors that implement
            // PriorityOrdered, Ordered, and the rest.
            List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
 
            //對(duì)于配置中讀取的 BeanDefinitionRegistryPostProcessor 的處理
            //首先處理 PriorityOrdered 接口的 BeanDefinitionRegistryPostProcessor
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();
 
            //接著處理 Ordered 接口的 BeanDefinitionRegistryPostProcessor
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();
 
            //最后再處理之前未注冊(cè)的 BeanDefinitionRegistryPostProcessor
            boolean reiterate = true;
            while (reiterate) {
                reiterate = false;
                postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
                for (String ppName : postProcessorNames) {
                    if (!processedBeans.contains(ppName)) {
                        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                        processedBeans.add(ppName);
                        reiterate = true;
                    }
                }
                sortPostProcessors(currentRegistryProcessors, beanFactory);
                registryProcessors.addAll(currentRegistryProcessors);
                invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
                currentRegistryProcessors.clear();
            }
 
            //激活所有的 BeanFactoryPostProcessor
            invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
            invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
        }
 
        else {
            // Invoke factory processors registered with the context instance.
            invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
        }
 
        //對(duì)于配置中讀取的 BeanFactoryPostProcessor 的處理
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
 
        // 對(duì)后處理器進(jìn)行分類
        List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
        List<String> orderedPostProcessorNames = new ArrayList<>();
        List<String> nonOrderedPostProcessorNames = new ArrayList<>();
        for (String ppName : postProcessorNames) {
            if (processedBeans.contains(ppName)) {
                // skip - already processed in first phase above
            }
            else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
            }
            else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                orderedPostProcessorNames.add(ppName);
            }
            else {
                nonOrderedPostProcessorNames.add(ppName);
            }
        }
 
        //按照優(yōu)先級(jí)排序
        sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
 
        //按照order排序
        List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
        for (String postProcessorName : orderedPostProcessorNames) {
            orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
        sortPostProcessors(orderedPostProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
 
        //直接調(diào)用
        List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
        for (String postProcessorName : nonOrderedPostProcessorNames) {
            nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
        invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
 
        //清空緩存
        beanFactory.clearMetadataCache();
    }

從上面的方法我們可以看到塘砸,對(duì)于BeanFactoryPostProcessor的處理主要分兩種情況進(jìn)行的节仿,一個(gè)是對(duì)于BeanDefinitionRegistry類的特殊處理,另一種是對(duì)普通的BeanFactoryPostProcessor進(jìn)行處理掉蔬。而對(duì)于每種情況都需要考慮硬編碼注入注冊(cè)的后處理器以及通過(guò)配置注入的后處理器廊宪。
對(duì)于BeanDefinitionRegistry類型的處理類的處理主要包括以下內(nèi)容:

(1)對(duì)于硬編碼注冊(cè)的后處理器的處理,主要是通過(guò)AbstractApplicationContext中的添加處理器方法addBeanFactoryPost Processor進(jìn)行添加

public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
    Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
    this.beanFactoryPostProcessors.add(postProcessor);
}

添加后的后處理器會(huì)存放在beanFactoryPostProcessors里女轿,而在處理BeanFactoryPostProcessor的時(shí)候會(huì)首先檢測(cè)beanFactory PostProcessors中是否有數(shù)據(jù)箭启。當(dāng)然,BeanDefinitionRegistryPostProcessor繼承自BeanFactoryPostProcessor蛉迹,不但有后者的全部特性傅寡,同時(shí)還有自己的個(gè)性化方法,也需要在此調(diào)用北救。所以荐操,這里需要從beanFactoryPostProcessor中挑出BeanDefinition RegistryPostProcessor的后處理器,并進(jìn)行其postProcessBeanDefinitionRegistry方法的激活珍策。

(2)記錄后處理器主要使用了三個(gè)List完成

i.regularPostProcessors:記錄通過(guò)硬編碼方式注冊(cè)的BeanFactoryPostProcessor類型的處理器

ii.registryProcessors:記錄BeanDefinitionRegistryPostProcessor類型的處理器

iii.currentRegistryProcessors:記錄當(dāng)前已經(jīng)注冊(cè)過(guò)的

BeanDefinitionRegistryPostProcessor類型的處理器托启。

(3)分別對(duì)實(shí)現(xiàn)了PriorityOrdered和Ordered接口的BeanDefinitionRegistryPostProcessor類型的處理器進(jìn)行排序

(4)調(diào)用激活方法對(duì)處理器進(jìn)行激活

(5)普通的后處理器的流程與BeanDefinitionRegistryPostProcessor類型的處理器流程大致相同,這里就不再贅述了攘宙。

這里需要強(qiáng)調(diào)的是屯耸,對(duì)于硬編碼方式手動(dòng)添加的后處理器是不需要做任何排序的拐迁,但是在配置文件中讀取的處理器,Spring并不保證讀取的順序肩民。所以唠亚,為了保證用戶的調(diào)用順序的要求,Spring對(duì)于后處理器的調(diào)用支持按照PriorityOrdered和Ordered的順序調(diào)用持痰。

2.注冊(cè)BeanPostProcessor

上文中提到了Bean提到了BeanFactoryPostProcessor的調(diào)用灶搜,現(xiàn)在我們來(lái)探索下BeanPostProcessor,但是這里并不是調(diào)用工窍,而是注冊(cè)割卖。真正的調(diào)用其實(shí)是在bean的實(shí)例化階段進(jìn)行的。這是一個(gè)很重要的步驟患雏,也是很多功能BeanFactory不支持的重要原因鹏溯。Spring中大部分功能都是通過(guò)后處理器的方式進(jìn)行擴(kuò)展的,這是Spring框架的一個(gè)特性淹仑,但是在BeanFactory中其實(shí)并沒(méi)有實(shí)現(xiàn)后處理器的自動(dòng)注冊(cè)丙挽,所以在調(diào)用的時(shí)候如果沒(méi)有進(jìn)行手動(dòng)注冊(cè)其實(shí)是不能使用的。但是在ApplicationContext中卻添加了自動(dòng)注冊(cè)功能匀借,如自定義這樣一個(gè)后處理器:

public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor{
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException{
System.out.println("=====");
return null;
}
}
在配置文件中添加配置:

<bean class="processors.MyInstantiationAwareBeanPostProcessor" />
那么使用BeanFactory方式進(jìn)行Spring的bean的加載是是不會(huì)有任何改變的颜阐,但是使用ApplicationContext方式獲取bean的時(shí)候會(huì)在獲取每個(gè)bean時(shí)打印出“====”,而這個(gè)特性就是在registerBeanPostProcessor方法中完成的吓肋。

我們繼續(xù)探索registerBeanPostProcessor的方法實(shí)現(xiàn)凳怨。

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

    // BeanPostProcessorChecker 是一個(gè)普通的信息打印,可能會(huì)有些情況:
    // 當(dāng)Spring的配置中的的后處理器還沒(méi)有被注冊(cè)就已經(jīng)開(kāi)始了bean的初始化時(shí)是鬼,
    // 便會(huì)打印出BeanPostProcessorChecker中設(shè)定的信息
    int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
    beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

    // 分別為實(shí)現(xiàn)了PriorityOrdered和Ordered接口的BeanPostProcessor保證順序
    List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
    List<String> orderedPostProcessorNames = new ArrayList<>();
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    for (String ppName : postProcessorNames) {
        if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            priorityOrderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
        }
        else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            orderedPostProcessorNames.add(ppName);
        }
        else {
            nonOrderedPostProcessorNames.add(ppName);
        }
    }

    // 首先排序并注冊(cè)實(shí)現(xiàn)了PriorityOrdered接口的BeanPostProcessor
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

    // 其次排序并注冊(cè)實(shí)現(xiàn)了Ordered接口的BeanPostProcessor
    List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
    for (String ppName : orderedPostProcessorNames) {
        BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        orderedPostProcessors.add(pp);
        if (pp instanceof MergedBeanDefinitionPostProcessor) {
            internalPostProcessors.add(pp);
        }
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, orderedPostProcessors);

    // 然后注冊(cè)正常的BeanPostProcessor
    List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
    for (String ppName : nonOrderedPostProcessorNames) {
        BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        nonOrderedPostProcessors.add(pp);
        if (pp instanceof MergedBeanDefinitionPostProcessor) {
            internalPostProcessors.add(pp);
        }
    }
    registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

    // 最后排序并注冊(cè)所有的實(shí)現(xiàn)了MergedBeanDefinitionPostProcessor接口的BeanPostProcessor
    // 這里并沒(méi)有重復(fù)注冊(cè)
    sortPostProcessors(internalPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, internalPostProcessors);

    // 添加ApplicationListener探測(cè)器
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

配合源碼以及注釋肤舞,在registerBeanPostProcessor方法中所做的邏輯相信大家都已經(jīng)很清楚了,我們?cè)僮鲆幌驴偨Y(jié)均蜜。

首先我們會(huì)發(fā)現(xiàn)李剖,對(duì)于BeanPostProcessor和BeanFactoryPostProcessor的處理極為相似,但是似乎又有一些不一樣的地方囤耳。經(jīng)過(guò)反復(fù)的對(duì)比發(fā)現(xiàn)杖爽,對(duì)于BeanFactoryPostProcessor的處理要區(qū)分兩種情況,一種方式是通過(guò)硬編碼方式的處理紫皇,另一種是通過(guò)配置文件方式的處理。那么為什么在BeanPostProcessor的處理中只考慮了配置文件的方式而不考慮硬編碼的方式呢腋寨?提出這個(gè)問(wèn)題聪铺,還是因?yàn)榇蠹覜](méi)有完全理解兩者實(shí)現(xiàn)的功能。對(duì)于BeanFactoryPostProcessor的處理萄窜,不但要實(shí)現(xiàn)注冊(cè)功能铃剔,而且還要實(shí)現(xiàn)對(duì)后處理器的激活操作撒桨,所以需要載入配置中的定義,并進(jìn)行激活:而對(duì)于BeanPostProcessor并不需要馬上調(diào)用键兜,再說(shuō)凤类,硬編碼的方式實(shí)現(xiàn)的功能是將后處理器提取并調(diào)用,這里并不需要調(diào)用當(dāng)然不需要硬編碼的方式了普气,這里的功能只需要將配置文件的BeanPostProcessor提取出來(lái)并注冊(cè)進(jìn)入beanFactory就可以了谜疤。

對(duì)于beanFactory的注冊(cè),也不是直接注冊(cè)就可以的现诀。在Spring中支持對(duì)于BeanPostProcessor的排序夷磕,比如根據(jù)PriorityOrdered進(jìn)行排序、根據(jù)Ordered進(jìn)行排序或者無(wú)序仔沿,而Spring在BeanPostProcessor的激活順序的時(shí)候也會(huì)考慮對(duì)于順序的問(wèn)題而先進(jìn)行排序坐桩。

這里有個(gè)地方讓人很迷惑,對(duì)于internalPostProcessor中存儲(chǔ)后處理器也就是MergedBeanDefinitionPostProcessor類型的處理器封锉,好像在代碼中重復(fù)注冊(cè)了绵跷,是這樣嗎?其實(shí)并不是的成福,我們可以看看對(duì)于registerBeanPostProcessor方法的實(shí)現(xiàn)方式碾局。

private static void registerBeanPostProcessors(
    ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {

    for (BeanPostProcessor postProcessor : postProcessors) {
        beanFactory.addBeanPostProcessor(postProcessor);
    }
}

public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
    Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
    this.beanPostProcessors.remove(beanPostProcessor);
    this.beanPostProcessors.add(beanPostProcessor);
    if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
        this.hasInstantiationAwareBeanPostProcessors = true;
    }
    if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
        this.hasDestructionAwareBeanPostProcessors = true;
    }
}

可以看到,在registerBeanPostProcessors方法的實(shí)現(xiàn)中其實(shí)已經(jīng)確保了BeanPostProcessor的唯一性闷叉,個(gè)人猜想擦俐,之所以選擇在registerBeanPostProcessor中沒(méi)有進(jìn)行重復(fù)移除操作或許是為了保持分類的效果,是邏輯更為清晰吧握侧。

3.初始化消息資源

在進(jìn)行這段函數(shù)的解析之前蚯瞧,我們先來(lái)回顧Spring國(guó)際化的使用方法。

假設(shè)我們正在開(kāi)發(fā)一個(gè)支持多國(guó)語(yǔ)言的Web應(yīng)用程序品擎,要求系統(tǒng)能夠根據(jù)客戶端的系統(tǒng)的語(yǔ)言類型返回對(duì)應(yīng)的界面:英文的操作系統(tǒng)返回英文界埋合,而中文的操作系統(tǒng)則返回中文界面——這是典型的i18n國(guó)際化問(wèn)題。對(duì)于有國(guó)際化要求的應(yīng)用系統(tǒng)萄传,我們不能簡(jiǎn)單的采用硬編碼的方式編寫(xiě)用戶界面信息甚颂、報(bào)錯(cuò)信息等內(nèi)容,而必須為這些需要國(guó)際化的信息進(jìn)行特殊處理秀菱。簡(jiǎn)單來(lái)說(shuō)振诬,就是為每種語(yǔ)言提供一種相應(yīng)的資源文件,并以規(guī)范化命名的方式保存在特定的目錄中衍菱,由系統(tǒng)自動(dòng)根據(jù)客戶端語(yǔ)言選擇合適的資源文件赶么。

“國(guó)際化信息”也稱為“本地化信息”,一般需要兩個(gè)條件才可以確定一個(gè)特定類型的本地化信息脊串,它們分別是“語(yǔ)言類型”和“國(guó)家/地區(qū)的類型”辫呻。如中文本地化信息既有中國(guó)大陸地區(qū)的中文清钥,又有中國(guó)臺(tái)灣地區(qū)。中國(guó)香港地區(qū)的中文放闺,還有新加坡地區(qū)的中文祟昭。Java通過(guò)java.util.Locale類表示一個(gè)本地化對(duì)象,它允許通過(guò)語(yǔ)言參數(shù)和國(guó)家/地區(qū)參數(shù)創(chuàng)建一個(gè)確定的本地化對(duì)象怖侦。

java.util.Locale是表示語(yǔ)言和國(guó)家/地區(qū)信息的本地化類篡悟,它是創(chuàng)建國(guó)際化應(yīng)用的基礎(chǔ)。下面給出幾個(gè)創(chuàng)建本地化對(duì)象的實(shí)例:

//帶有語(yǔ)言和國(guó)家/地區(qū)信息的本地化對(duì)象
Locale locale1 = new Locale("zh", "CN");

//只有語(yǔ)言信息的本地化對(duì)象
Locale locale2 = new Locale("zh");

//等同于locale1
Locale locale3 = Locale.CHINA;

//等同于locale2
Locale locale4 = Locale.CHINESE础钠;

//獲取本地系統(tǒng)默認(rèn)的本地化對(duì)象
Locale locale5 = Locale.getDefault();
JDK的java.util包提供了幾個(gè)支持本地化的格式化操作工具類:NumberFormat恰力、DateFormat、MessageFormat旗吁,而在Spring中的國(guó)際化資源操作也無(wú)非是對(duì)于這些類的封裝操作踩萎,我們僅僅介紹下MessageFormat的用法以幫助大家回顧

//信息格式化串
String pattern1 = "{0}, 你好!你與{1}在工商銀行存入{2}元很钓。";
String pattern2 = "At {1, time, short} On {1, date, long}, {0} paid {2, number, currency}.";

//用于動(dòng)態(tài)替換占位符的參數(shù)
Object[] params = {"John", new GregorianCalendar().getTime(), 1.0E3};

//使用默認(rèn)本地化對(duì)象格式化信息
String msg1 = MessageFormat.format(pattern1, params);

//使用指定的本地化對(duì)象格式化的信息
MessageFormat mf = new MessageFormat(pattern2, Locale.US);
String msg2 = mf.format(params);
System.out.println(msg1);
System.out.println(msg2);
Spring定義了訪問(wèn)國(guó)際化信息的MessageSource接口香府,并提供了幾個(gè)易用的實(shí)現(xiàn)類。MessageSource分別被HierarchicalMessage Source和ApplicationContext接口擴(kuò)展码倦,這里我們主要看一下HierarchicalMessageSource接口的幾個(gè)實(shí)現(xiàn)類:

HierarchicalMessageSource接口最重要的兩個(gè)實(shí)現(xiàn)類是ResourceBundleMessageSource和ReloadableResourceBundleMessage Source企孩。它們基于Java的ResourceBundle基礎(chǔ)類實(shí)現(xiàn),允許僅通過(guò)資源名加載國(guó)際化資源袁稽。ReloadableResourceBundleMessage Source提供了定時(shí)刷新功能勿璃,允許在不重啟系統(tǒng)的情況下,更新資源信息推汽。StaticMessageSource主要用于程序測(cè)試补疑,它允許通過(guò)編程的方式提供國(guó)家化信息。而DelegatingMessageSource是為方便操作父MessageSource而提供的代理類歹撒。僅僅舉例ResourceBundleMessageSource的實(shí)現(xiàn)方式:

(1)定義資源文件

messages.properties(默認(rèn):英文)

test=test
messages_zh_CN.properties(簡(jiǎn)體中文)

test=測(cè)試
(2)定義配置文件

<bean id="messageSource" class="org.Springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
<list>
<value>test/messages</value>
</list>
</property>
</bean>
其中莲组,這個(gè)Bean的ID必須命名為messageSource,否則會(huì)拋出NoSuchMessageException異常

(3)使用暖夭。通過(guò)ApplicationContext訪問(wèn)國(guó)際化信息锹杈。

String[] configs = {"applicationContext.xml"};
ApplicationContext ctx = new ClassPathXmlApplicationContext(configs);
//直接通過(guò)容器訪問(wèn)國(guó)際化信息
Object[] params = {"John", new GregorianCalendar.getTime()};
String str1 = ctx.getMessage("test", params, Locale.US);
String str2 = ctx.getMessage("test", params, Locale.CHINA);
System.out.println(str1);
System.out.println(str2);
了解了Spring國(guó)際化的使用后便可以進(jìn)行源碼的分析了。

在initMessageSource中的方法主要功能是提取配置中定義的messageSource迈着,并將其記錄在Spring的容器中竭望,也就是AbstractApplicationContext中,當(dāng)然裕菠,如果用戶未設(shè)置資源文件的話咬清,Spring中也提供了默認(rèn)的配置DelegatingMessageSource。

在initMessageSource中獲取自定義資源文件的方式為beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, Message Source.class),在這里Spring使用了硬編碼的方式硬性規(guī)定了自定義資源的文件的ID必須為messageSource枫振,否則便會(huì)獲取不到自定義資源配置,這也就是為什么前面提到的Bean的id如果不為messageSource會(huì)拋出異常萤彩。下面來(lái)看一下代碼:

protected void initMessageSource() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
        //如果在配置中已經(jīng)配置了messageSource粪滤,那么將messageSource提取并記錄在this.messageSource中
        this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
        // Make MessageSource aware of parent MessageSource.
        if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
            HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
            if (hms.getParentMessageSource() == null) {
                // Only set parent context as parent MessageSource if no parent MessageSource
                // registered already.
                hms.setParentMessageSource(getInternalParentMessageSource());
            }
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Using MessageSource [" + this.messageSource + "]");
        }
    }
    else {
        // 如果用戶沒(méi)有定義配置文件,那么使用臨時(shí)的DelegatingMessageSource以便于調(diào)用getMessage方法的返回
        DelegatingMessageSource dms = new DelegatingMessageSource();
        dms.setParentMessageSource(getInternalParentMessageSource());
        this.messageSource = dms;
        beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
                    "': using default [" + this.messageSource + "]");
        }
    }
}

通過(guò)讀取并將自定義資源文件配置記錄在容器中雀扶,那么就可以在獲取資源文件的時(shí)候直接使用了杖小,例如在AbstractApplicationContext中的獲取資源文件屬性的方法:

public String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
    return getMessageSource().getMessage(code, args, locale);
}

其中的getMessageSource()方法正是獲取了之前定義的自定義資源配置

4.初始化ApplicationEventMulticaster

在講解Spring的時(shí)間傳播器之前,我們還是先來(lái)看一下Spring的時(shí)間監(jiān)聽(tīng)的簡(jiǎn)單用法愚墓。

(1)定義監(jiān)聽(tīng)時(shí)間

public class TestEvent extends ApplicationEvent{
public String msg;
public TestEvent(Object source){
super(source);
}

public TestEvent(Object source, String msg){
    super(source);
    this.msg = msg;
}

public void print(){
    System.out.println(msg);
}

}
(2)定義監(jiān)聽(tīng)器

public class TestListener implements ApplicationListener{
public void onApplicationEvent(ApplicationEvent event){
if(event instancof TestEvent){
TestEvent testEvent = (TestEvent)event;
testEvent.print();
}
}
}
(3)添加配置文件

<bean id="testListener" class="com.test.event.TestListener" />
(4)測(cè)試

public class Test{
public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
TestEvent event = new TestEvent("hello", "msg");
ctx.publishEvent(event);
}
}
當(dāng)程序運(yùn)行時(shí)予权,Spring會(huì)將發(fā)出的TestEvent事件轉(zhuǎn)給我們自定義的TestListener進(jìn)行進(jìn)一步處理。

或許很多人一下子會(huì)反應(yīng)這是設(shè)計(jì)模式中的觀察者模式浪册,這確實(shí)是個(gè)典型的應(yīng)用扫腺,可以在比較關(guān)心的事件結(jié)束后及時(shí)處理。那么我們看看ApplicationEventMulticaster是如何被初始化的村象,以確保功能的正確運(yùn)行笆环。

initApplicationEventMulticaster的方式比較簡(jiǎn)單,無(wú)非考慮兩種情況厚者。

i.如果用戶自定義了事件廣播器躁劣,那么使用用戶自定義的事件廣播器

ii.如果用戶沒(méi)有自定義事件廣播器,那么使用默認(rèn)的ApplicationEventMulticaster库菲。

protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
        }
    }
    else {
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                    APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                    "': using default [" + this.applicationEventMulticaster + "]");
        }
    }
}

按照之前介紹的順序及邏輯账忘,我們推斷,作為廣播器熙宇,一定是用于存放監(jiān)聽(tīng)器并在合適的時(shí)候調(diào)用監(jiān)聽(tīng)器鳖擒,那么我們不妨進(jìn)入默認(rèn)的廣播器實(shí)現(xiàn)SimpleApplicationEventMulticaster來(lái)一探究竟。

其中一段代碼使我們感興趣的奇颠。

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        Executor executor = getTaskExecutor();
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            invokeListener(listener, event);
        }
    }
}

可以推斷败去,當(dāng)產(chǎn)生Spring事件的時(shí)候會(huì)默認(rèn)使用SimpleApplicationEventMulticaster的multicasterEvent來(lái)廣播事件,遍歷所有監(jiān)聽(tīng)器烈拒,并使用監(jiān)聽(tīng)器中的onApplicationEvent方法來(lái)進(jìn)行監(jiān)聽(tīng)器的處理圆裕。而對(duì)于每個(gè)監(jiān)聽(tīng)器來(lái)說(shuō)其實(shí)都可以獲取到產(chǎn)生的時(shí)間,但是是否進(jìn)行處理則由事件監(jiān)聽(tīng)器決定荆几。

5.注冊(cè)監(jiān)聽(tīng)器

之前介紹Spring的廣播器時(shí)反復(fù)提到了事件監(jiān)聽(tīng)器吓妆,那么在Spring注冊(cè)監(jiān)聽(tīng)器的時(shí)候又做了哪些邏輯操作呢?

protected void registerListeners() {
    // 硬編碼注冊(cè)監(jiān)聽(tīng)器
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // 配置文件注冊(cè)監(jiān)聽(tīng)器
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // Publish early application events now that we finally have a multicaster...
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (earlyEventsToProcess != null) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

初始化非延遲加載單例

完成BeanFactory的初始化工作吨铸,其中包括ConversionService的設(shè)置行拢、配置凍結(jié)以及非延遲加載的bean的初始化工作。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service for this context.
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
            beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
                beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }

    // Register a default embedded value resolver if no bean post-processor
    // (such as a PropertyPlaceholderConfigurer bean) registered any before:
    // at this point, primarily for resolution in annotation attribute values.
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }

    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }

    // Stop using the temporary ClassLoader for type matching.
    beanFactory.setTempClassLoader(null);

    // 凍結(jié)所有的bean定義诞吱,說(shuō)明注冊(cè)的bean定義將不被修改或任何進(jìn)一步的處理
    beanFactory.freezeConfiguration();

    // 初始化剩下的單實(shí)例(非惰性的)
    beanFactory.preInstantiateSingletons();
}

首先我們來(lái)了解一下ConversionService類所提供的作用舟奠。

1.ConversionService的設(shè)置

之前我們提到過(guò)使用自定義類型轉(zhuǎn)換器從String轉(zhuǎn)換為Date的方式竭缝,那么,在Spring中還提供了另一種轉(zhuǎn)換方式:使用Converter沼瘫。同樣抬纸,我們使用一個(gè)簡(jiǎn)單的實(shí)例來(lái)了解下Converter的使用方式。

(1)定義轉(zhuǎn)換器

public class String2DateConverter implements Converter<String, Date>{
@Override
public Date convert(String arg0){
try{
return DateUtil.parseDate(arg0,
new String[]("yyyy-MM-dd HH:mm:ss"));
}catch(ParseException e){
return null;
}
}
}
(2)注冊(cè)

<bean id="conversionService" class="org.Springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="String2DateConverter" />
</list>
</property>
</bean>
(3)測(cè)試

這樣便可以使用Converter為我們提供的功能了耿戚,下面我們通過(guò)一個(gè)簡(jiǎn)便的方法來(lái)對(duì)此直接測(cè)試湿故。

public void testString2DateConvert(){
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new String2DateConverter());
String dateStr = "2018-07-04 10:00:00";
Date date = conversionService.convert(dateStr, Date.class);
}
通過(guò)以上的功能我們看到了Converter以及ConversionService提供的便利功能,其中的配置就是在當(dāng)前函數(shù)中被初始化的膜蛔。

2.凍結(jié)配置

凍結(jié)所有的bean定義坛猪,說(shuō)明注冊(cè)的bean定義將不被修改或進(jìn)行任何進(jìn)一步的處理。

public void freezeConfiguration() {
    this.configurationFrozen = true;
    this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
}

3.初始化非延遲加載

ApplicationContext實(shí)現(xiàn)的默認(rèn)行為就是在啟動(dòng)時(shí)將所有單例bean提前進(jìn)行實(shí)例化皂股。提前實(shí)例意味著作初始化過(guò)程的一部分墅茉,ApplicationContext實(shí)例會(huì)創(chuàng)建并配置所有的單例bean。通常情況下這是一件好事屑墨,因?yàn)檫@樣在配置中的任何錯(cuò)誤就會(huì)即刻發(fā)現(xiàn)(否則的話可能要花幾個(gè)小時(shí)甚至幾天)躁锁。而這個(gè)實(shí)例化的過(guò)程就是在finishBeanFactoryInitialization中完成的。

public void preInstantiateSingletons() throws BeansException {
    if (this.logger.isDebugEnabled()) {
        this.logger.debug("Pre-instantiating singletons in " + this);
    }

    // Iterate over a copy to allow for init methods which in turn register new bean definitions.
    // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // Trigger initialization of all non-lazy singleton beans...
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    final FactoryBean<?> factory = (FactoryBean<?>) bean;
                    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(beanName);
                    }
                }
            }
            else {
                getBean(beanName);
            }
        }
    }

    // Trigger post-initialization callback for all applicable beans...
    for (String beanName : beanNames) {
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton) {
            final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    smartSingleton.afterSingletonsInstantiated();
                    return null;
                }, getAccessControlContext());
            }
            else {
                smartSingleton.afterSingletonsInstantiated();
            }
        }
    }
}

finishRefresh

在Spring中還提供了Lifecycle接口卵史,Lifecycle中包含了start/stop方法战转,實(shí)現(xiàn)此接口后Spring會(huì)保證在啟動(dòng)的時(shí)候調(diào)用其start方法開(kāi)始生命周期,并在Spring關(guān)閉的時(shí)候調(diào)用stop方法來(lái)結(jié)束生命周期以躯,通常用來(lái)配置后臺(tái)程序槐秧,在啟動(dòng)后一直運(yùn)行(如對(duì)MQ進(jìn)行輪詢等)。而ApplicationContext的初始化最后正是保證了這一功能的實(shí)現(xiàn)忧设。

protected void finishRefresh() {
    // Clear context-level resource caches (such as ASM metadata from scanning).
    clearResourceCaches();

    // Initialize lifecycle processor for this context.
    initLifecycleProcessor();

    // Propagate refresh to lifecycle processor first.
    getLifecycleProcessor().onRefresh();

    // Publish the final event.
    publishEvent(new ContextRefreshedEvent(this));

    // Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}

1.initLifecycleProcess

當(dāng)ApplicationContext啟動(dòng)或停止時(shí)刁标,它會(huì)通過(guò)LifecycleProcessor來(lái)與所有聲明的bean的周期做狀態(tài)更新,而在LifecycleProcessor的使用前首先需要初始化址晕。

protected void initLifecycleProcessor() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
        this.lifecycleProcessor =
                beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
        }
    }
    else {
        DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
        defaultProcessor.setBeanFactory(beanFactory);
        this.lifecycleProcessor = defaultProcessor;
        beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate LifecycleProcessor with name '" +
                    LIFECYCLE_PROCESSOR_BEAN_NAME +
                    "': using default [" + this.lifecycleProcessor + "]");
        }
    }
}

2.onRefresh

啟動(dòng)所有實(shí)現(xiàn)了Lifecycle接口的bean膀懈。

public void onRefresh() {
    startBeans(true);
    this.running = true;
}

private void startBeans(boolean autoStartupOnly) {
    Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
    Map<Integer, LifecycleGroup> phases = new HashMap<>();
    lifecycleBeans.forEach((beanName, bean) -> {
        if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
            int phase = getPhase(bean);
            LifecycleGroup group = phases.get(phase);
            if (group == null) {
                group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
                phases.put(phase, group);
            }
            group.add(beanName, bean);
        }
    });
    if (!phases.isEmpty()) {
        List<Integer> keys = new ArrayList<>(phases.keySet());
        Collections.sort(keys);
        for (Integer key : keys) {
            phases.get(key).start();
        }
    }
}

3.publishEvent

當(dāng)完成ApplicationContext初始化的時(shí)候,要通過(guò)Spring中的時(shí)間發(fā)布機(jī)制來(lái)發(fā)出ContextRefreshEvent事件谨垃,以保證對(duì)應(yīng)的監(jiān)聽(tīng)器可以做進(jìn)一步的邏輯處理启搂。

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");
    if (logger.isTraceEnabled()) {
        logger.trace("Publishing event in " + getDisplayName() + ": " + event);
    }

    // Decorate event as an ApplicationEvent if necessary
    ApplicationEvent applicationEvent;
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent) event;
    }
    else {
        applicationEvent = new PayloadApplicationEvent<>(this, event);
        if (eventType == null) {
            eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
        }
    }

    // Multicast right now if possible - or lazily once the multicaster is initialized
    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    }
    else {
        getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }

    // Publish event via parent context as well...
    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
        }
        else {
            this.parent.publishEvent(event);
        }
    }
}

至此,ApplicationContext相比于BeanFactory擴(kuò)展的功能以及相關(guān)代碼我們就了解完了刘陶,下一篇文章我們將會(huì)看一看Spring中另一個(gè)重要的思想AOP(面向切面編程)是如何實(shí)現(xiàn)的胳赌。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市匙隔,隨后出現(xiàn)的幾起案子疑苫,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捍掺,死亡現(xiàn)場(chǎng)離奇詭異撼短,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)挺勿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)阔加,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人满钟,你說(shuō)我怎么就攤上這事「炫纾” “怎么了湃番?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)吭露。 經(jīng)常有香客問(wèn)我吠撮,道長(zhǎng),這世上最難降的妖魔是什么讲竿? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任泥兰,我火速辦了婚禮,結(jié)果婚禮上题禀,老公的妹妹穿的比我還像新娘鞋诗。我一直安慰自己,他們只是感情好迈嘹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布削彬。 她就那樣靜靜地躺著,像睡著了一般秀仲。 火紅的嫁衣襯著肌膚如雪融痛。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,462評(píng)論 1 302
  • 那天神僵,我揣著相機(jī)與錄音雁刷,去河邊找鬼。 笑死保礼,一個(gè)胖子當(dāng)著我的面吹牛沛励,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播氓英,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼侯勉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了铝阐?” 一聲冷哼從身側(cè)響起址貌,我...
    開(kāi)封第一講書(shū)人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后练对,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體遍蟋,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年螟凭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了虚青。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡螺男,死狀恐怖棒厘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情下隧,我是刑警寧澤奢人,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站淆院,受9級(jí)特大地震影響何乎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜土辩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一支救、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拷淘,春花似錦各墨、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至逝嚎,卻和暖如春扁瓢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背补君。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工引几, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挽铁。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓伟桅,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親叽掘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子楣铁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容