ClassPathXmlApplicationContext的啟動(dòng)

Spring將ApplicationContext啟動(dòng)的全過程,refresh函數(shù)中包含了幾乎ApplicationContext中提供的全部功能,而且此函數(shù)中邏輯非常清晰明了,很容易分析對(duì)應(yīng)的層次及邏輯。:
ClassPathXmlApplicationContext相比于XmlBeanFactory是在DefaultListableBeanFactory基礎(chǔ)上多了一系列的擴(kuò)展。

ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            //準(zhǔn)備刷新的上下文環(huán)境,例如對(duì)系統(tǒng)屬性或者環(huán)境變量進(jìn)行準(zhǔn)備及驗(yàn)證。
            prepareRefresh();
            //初始化BeanFactory,并進(jìn)行XML文件讀取,
            //這一步之后,ClassPathXmlApplicationContext實(shí)際上就已經(jīng)包含了BeanFactory所提供的功能,也就是可以進(jìn)行Bean的提取等基礎(chǔ)操作了。
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            //對(duì)BeanFactory進(jìn)行各種功能填充,@Qualifier與@Autowired這兩個(gè)注解正是在這一步驟中增加的支持。
            //設(shè)置@Autowired和 @Qualifier注解解析器QualifierAnnotationAutowireCandidateResolver
       prepareBeanFactory(beanFactory);
            try {
                //子類覆蓋方法做額外的處理,提供了一個(gè)空的函數(shù)實(shí)現(xiàn)postProcessBeanFactory來方便程序員在業(yè)務(wù)上做進(jìn)一步擴(kuò)展。
                postProcessBeanFactory(beanFactory);
                //激活各種BeanFactory處理器
                invokeBeanFactoryPostProcessors(beanFactory);
                //注冊攔截Bean創(chuàng)建的Bean處理器,這里只是注冊,真正的調(diào)用是在getBean時(shí)候
                registerBeanPostProcessors(beanFactory);
                //為上下文初始化Message源,即不同語言的消息體進(jìn)行國際化處理
                initMessageSource();
                //初始化應(yīng)用消息廣播器,并放入“applicationEventMulticaster”bean中
                initApplicationEventMulticaster();
                //留給子類來初始化其它的Bean
                onRefresh();
                //在所有注冊的bean中查找Listener bean,注冊到消息廣播器中
                registerListeners();
                //初始化剩下的單實(shí)例(非惰性的)
                finishBeanFactoryInitialization(beanFactory);
                //完成刷新過程,通知生命周期處理器lifecycleProcessor刷新過程,同時(shí)發(fā)出ContextRefreshEvent通知?jiǎng)e人
                finishRefresh();
            }
            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

環(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();
     //to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
    }

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

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{ 
  public MyClassPathXmlApplicationContext(String... configLocations ){       
     super(configLocations);
  } 
protected void initPropertySources() { //添加驗(yàn)證要求
        getEnvironment().setRequiredProperties("classpath");
    }
}

我們自定義了繼承自ClassPathXmlApplicationContext的MyClassPathXmlApplicationContext,并重寫了initPropertySources方法,在方法中添加了我們的個(gè)性化需求,那么在驗(yàn)證的時(shí)候也就是程序走到getEnvironment().validateRequiredProperties()代碼的時(shí)候,如果系統(tǒng)并沒有檢測到對(duì)應(yīng)classpath的環(huán)境變量,那么將拋出異常。

加載BeanFactory

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        //初始化BeanFactory,并進(jìn)行XML文件讀取,并將得到的BeanFacotry記錄在當(dāng)前實(shí)體的屬性中
        refreshBeanFactory();
        //返回當(dāng)前實(shí)體的beanFactory屬性
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }

    AbstractRefreshableApplicationContext.java
    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            //在介紹BeanFactory的時(shí)候,聲明方式為:BeanFactory bf = new XmlBeanFactory("beanFactoryTest.xml"),
       //其中的XmlBeanFactory繼承自DefaultListableBeanFactory,并提供了XmlBeanDefinitionReader類型的reader屬性,
       //也就是說DefaultListableBean Factory是容器的基礎(chǔ)。必須首先要實(shí)例化,那么在這里就是實(shí)例化DefaultListableBeanFactory的步驟。
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            //為了序列化指定id,如果需要的話,讓這個(gè)BeanFactory從id反序列化到BeanFactory對(duì)象
            beanFactory.setSerializationId(getId());
            //定制beanFactory,設(shè)置相關(guān)屬性,包括是否允許覆蓋同名稱的不同定義的對(duì)象以及循環(huán)依賴以及
            customizeBeanFactory(beanFactory);
            //初始化DodumentReader,并進(jìn)行XML文件讀取及解析
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                //使用全局變量記錄BeanFactory類實(shí)例。
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }


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


    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        //為指定beanFactory創(chuàng)建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);
        //使用XmlBeanDefinitionReader的loadBeanDefinitions方法進(jìn)行配置文件的加載及注冊
        loadBeanDefinitions(beanDefinitionReader);
    }

功能擴(kuò)展

 protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        //設(shè)置beanFactory的classLoader為當(dāng)前context的classLoader
        beanFactory.setBeanClassLoader(getClassLoader());
        //設(shè)置beanFactory的表達(dá)式語言處理器,Spring3增加了表達(dá)式語言的支持,SPEL語言。
        //默認(rèn)可以使用#{bean.xxx}的形式來調(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
        //ApplicationContextAwareProcessor實(shí)現(xiàn)了BeanPostProcessor接口,在bean實(shí)例化的時(shí)候會(huì)被調(diào)用
        //postProcessBeforeInitialization方法中調(diào)用了invokeAwareInterfaces。從invokeAwareInterfaces方法中,
    ?。覀兛梢钥闯鰜?,實(shí)現(xiàn)這些Aware接口的bean在被初始化之后,可以取得一些對(duì)應(yīng)的資源。
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        //Spring將ApplicationContextAwareProcessor注冊后,在invokeAwareInterfaces方法中間調(diào)用的Aware類已經(jīng)不是普通的bean了,
        //如ResourceLoaderAware,ApplicationEventPublisherAware等,需要在Spring做bean的依賴注入的時(shí)候忽略它們。
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

        //設(shè)置了幾個(gè)自動(dòng)裝配的特殊規(guī)則  
        //當(dāng)注冊了依賴解析后,例如當(dāng)注冊了對(duì)BeanFactory.class的解析后,當(dāng)bean的屬性注入的時(shí)候,
     //一旦檢測到屬性為BeanFactory類型便會(huì)將beanFactory的實(shí)例注入進(jìn)去。
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, 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()));
        }

        //將相關(guān)環(huán)境變量及屬性注冊以單例模式注冊,environment,systemProperties,systemEnvironment
        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());
        }
    }


ResourceEditorRegistrar的registerCustomEditors的調(diào)用時(shí)機(jī),就是AbstractBeanFactory類中的initBeanWrapper方法,這是在bean初始化時(shí)使用的一個(gè)方法,主要是在將BeanDefinition轉(zhuǎn)換為BeanWrapper后用于對(duì)屬性的填充。在bean的初始化后會(huì)調(diào)用ResourceEditorRegistrar的registerCustomEditors方法進(jìn)行批量的通用屬性編輯器注冊。注冊后,在屬性填充的環(huán)節(jié)便可以直接讓Spring使用這些編輯器進(jìn)行屬性的解析了。
Spring中用于封裝bean的是BeanWrapper類型,而它又間接繼承了PropertyEditorRegistry類型,也就是我們之前反復(fù)看到的方法參數(shù)PropertyEditorRegistry,其實(shí)大部分情況下都是BeanWrapper,對(duì)于BeanWrapper在Spring中的默認(rèn)實(shí)現(xiàn)是BeanWrapperImpl,而BeanWrapperImpl除了實(shí)現(xiàn)BeanWrapper接口外還繼承了PropertyEditorRegistrySupport,在PropertyEditorRegistrySupport中有這樣一個(gè)方法:createDefaultEditors,基本的屬性編輯器就在此處被注冊。
BeanFactory的后處理
BeanFactoryPostProcessor接口跟BeanPostProcessor類似,可以對(duì)bean的定義(配置元數(shù)據(jù))進(jìn)行處理。也就是說,Spring IoC容器允許BeanFactoryPostProcessor在容器實(shí)際實(shí)例化任何其他的bean之前讀取配置元數(shù)據(jù),并有可能修改它。如果你愿意,你可以配置多個(gè)BeanFactoryPostProcessor。你還能通過設(shè)置“order”屬性來控制BeanFactoryPostProcessor的執(zhí)行次序(僅當(dāng)BeanFactoryPostProcessor實(shí)現(xiàn)了Ordered接口時(shí)你才可以設(shè)置此屬性,因此在實(shí)現(xiàn)BeanFactoryPostProcessor時(shí),就應(yīng)當(dāng)考慮實(shí)現(xiàn)Ordered接口)。

如果你想改變實(shí)際的bean實(shí)例(例如從配置元數(shù)據(jù)創(chuàng)建的對(duì)象),那么你最好使用BeanPostProcessor。同樣地,BeanFactoryPostProcessor的作用域范圍是容器級(jí)的。它只和你所使用的容器有關(guān)。如果你在容器中定義一個(gè)BeanFactoryPostProcessor,它僅僅對(duì)此容器中的bean進(jìn)行后置處理。BeanFactoryPostProcessor不會(huì)對(duì)定義在另一個(gè)容器中的bean進(jìn)行后置處理,即使這兩個(gè)容器都是在同一層次上。

在Spring中存在對(duì)于BeanFactoryPostProcessor的兩種典型應(yīng)用。

(1)比如PropertyPlaceholderConfigurer

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="locations">
   <list>
    <value>/WEB-INF/mail.properties</value>  
    <value>classpath: conf/sqlmap/jdbc.properties</value>//注意這兩種value值的寫法
   </list>
  </property>
   <property name="fileEncoding">
     <value>UTF-8</value>
   </property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <property name="driverClassName"value="${jdbc.driverClassName}" />
  <property name="url" value="${jdbc.url}" />
  <property name="username" value="${jdbc.username}"/>
  <property name="password"value="${jdbc.password}" />
</bean>

jdbc.properties文件
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/mysqldb?useUnicode=true&amp;characterEncoding=UTF-8&amp;
jdbc.username=root
jdbc.password=123456

PropertyPlaceholderConfigurer是個(gè)bean工廠后置處理器的實(shí)現(xiàn),也就是BeanFactoryPostProcessor接口的一個(gè)實(shí)現(xiàn)。PropertyPlaceholderConfigurer可以將上下文(配置文件)中的屬性值放在另一個(gè)單獨(dú)的標(biāo)準(zhǔn)java Properties文件中去。在XML文件中用${key}替換指定的properties文件中的值。這樣的話,只需要對(duì)properties文件進(jìn)行修改,而不用對(duì)xml配置文件進(jìn)行修改。
在Spring中,使用PropertyPlaceholderConfigurer可以在XML配置文件中加入外部屬性文件,當(dāng)然也可以指定外部文件的編碼,PropertyPlaceholderConfigurer如果在指定的Properties文件中找不到你想使用的屬性,它還會(huì)在Java的System類屬性中查找。可以通過System.setProperty(key, value)或者java中通過-Dnamevalue來給Spring配置文件傳遞參數(shù)。

查看層級(jí)結(jié)構(gòu)可以看出PropertyPlaceholderConfigurer這個(gè)類間接繼承了BeanFactoryPostProcessor接口。這是一個(gè)很特別的接口,當(dāng)Spring加載任何實(shí)現(xiàn)了這個(gè)接口的bean的配置時(shí),都會(huì)在bean工廠載入所有bean的配置之后執(zhí)行postProcessBeanFactory方法。在PropertyResourceConfigurer類中實(shí)現(xiàn)了postProcessBeanFactory方法,在方法中先后調(diào)用了mergeProperties、convertProperties、processProperties這3個(gè)方法,分別得到配置,將得到的配置轉(zhuǎn)換為合適的類型,最后將配置內(nèi)容告知BeanFactory。正是通過實(shí)現(xiàn)BeanFactoryPostProcessor接口,BeanFactory會(huì)在實(shí)例化任何bean之前獲得配置信息,從而能夠正確解析bean描述文件中的變量引用。

(2)使用自定義BeanFactoryPostProcessor

實(shí)現(xiàn)一個(gè)BeanFactoryPostProcessor,實(shí)現(xiàn)一個(gè)簡單的回調(diào)處理器,它能去除潛在的"流氓"屬性值,例如bean定義中留下bollocks這樣的字眼。

<bean id="bfpp" class="com.spring.ch04.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.ch04.SimplePostProcessor">  
    <property name="connectionString" value="bollocks"/>  
    <property name="password" value="imaginecup"/>  
    <property name="username" value="Microsoft"/>  
</bean>  

java代碼

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 valueResover=new StringValueResolver() {  
                public String resolveStringValue(String strVal) {  
                    if(isObscene(strVal)) return "*****";  
                    return strVal;  
                }  
            };  
            BeanDefinitionVisitor visitor=new BeanDefinitionVisitor(valueResover);  
            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 obscenity:obscenties){  
            this.obscenties.add(obscenity.toUpperCase());  
        }  
    }  
  
}  

測試類

import org.springframework.beans.factory.config.BeanFactoryPostProcessor;  
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;  
import org.springframework.beans.factory.xml.XmlBeanFactory;  
import org.springframework.core.io.ClassPathResource;  
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"));  
          
    }  
}  

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

激活BeanFactoryPostProcessor

1)從invokeBeanFactoryPostProcessors的方法中我們看到,對(duì)于BeanFactoryPostProcessor的處理主要分兩種情況進(jìn)行,一個(gè)是對(duì)于BeanDefinitionRegistry類的特殊處理,另一種是對(duì)普通的BeanFactoryPostProcessor進(jìn)行處理。而對(duì)于每種情況都需要考慮硬編碼注入注冊的后處理器以及通過配置注入的后處理器。

對(duì)于硬編碼注冊的后處理器的處理,主要是通過AbstractApplicationContext中的添加處理器方法addBeanFactoryPostProcessor進(jìn)行添加。

public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {

this.beanFactoryPostProcessors.add(beanFactoryPostProcessor);

}

添加后的后處理器會(huì)存放在beanFactoryPostProcessors中,而在處理BeanFactoryPostProcessor時(shí)候會(huì)首先檢測beanFactoryPostProcessors是否有數(shù)據(jù)。當(dāng)然,BeanDefinitionRegistryPostProcessor繼承自BeanFactoryPostProcessor,不但有BeanFactoryPostProcessor的特性,同時(shí)還有自己定義的個(gè)性化方法,也需要在此調(diào)用。所以,這里需要從beanFactoryPostProcessors中挑出BeanDefinitionRegistryPostProcessor的后處理器,并進(jìn)行其postProcessBeanDefinitionRegistry方法的激活。

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

registryPostProcessors:記錄通過硬編碼方式注冊的BeanDefinitionRegistryPostProcessor類型的處理器。

regularPostProcessors:記錄通過硬編碼方式注冊的BeanFactoryPostProcessor類型的處理器。

registryPostProcessorBeans:記錄通過配置方式注冊的BeanDefinitionRegistryPostProcessor類型的處理器。

(3)對(duì)以上所記錄的List中的后處理器進(jìn)行統(tǒng)一調(diào)用BeanFactoryPostProcessor的postProcessBeanFactory方法。

(4)對(duì)beanFactoryPostProcessors中非BeanDefinitionRegistryPostProcessor類型的后處理器進(jìn)行統(tǒng)一的BeanFactoryPostProcessor的postProcessBeanFactory方法調(diào)用。

(5)普通beanFactory處理。BeanDefinitionRegistryPostProcessor只對(duì)BeanDefinitionRegistry類型的ConfigurableListableBeanFactory有效,所以如果判斷所示的beanFactory并不是BeanDefinitionRegistry,那么便可以忽略BeanDefinitionRegistryPostProcessor,而直接處理BeanFactoryPostProcessor,當(dāng)然獲取的方式與上面的獲取類似。

對(duì)于硬編碼方式手動(dòng)添加的后處理器是不需要做任何排序的,但是在配置文件中讀取的處理器,Spring并不保證讀取的順序。所以,為了保證用戶的調(diào)用順序的要求,Spring對(duì)于后處理器的調(diào)用支持按照PriorityOrdered或者Ordered的順序調(diào)用。

注冊BeanPostProcessor

來探索下BeanPostProcessor,但是這里并不是調(diào)用,而是注冊。真正的調(diào)用其實(shí)是在bean的實(shí)例化階段進(jìn)行的。這是一個(gè)很重要的步驟,也是很多功能BeanFactory不支持的重要原因。Spring中大部分功能都是通過后處理器的方式進(jìn)行擴(kuò)展的,這是Spring框架的一個(gè)特性,但是在BeanFactory中其實(shí)并沒有實(shí)現(xiàn)后處理器的自動(dòng)注冊,所以在調(diào)用的時(shí)候如果沒有進(jìn)行手動(dòng)注冊其實(shí)是不能使用的。

對(duì)于BeanPostProcessor的處理與BeanFactoryPostProcessor的處理極為相似,但是似乎又有些不一樣的地方。經(jīng)過反復(fù)的對(duì)比發(fā)現(xiàn),對(duì)于BeanFactoryPostProcessor的處理要區(qū)分兩種情況,一種方式是通過硬編碼方式的處理,另一種是通過配置文件方式的處理。那么為什么在BeanPostProcessor的處理中只考慮了配置文件的方式而不考慮硬編碼的方式呢?對(duì)于BeanFactoryPostProcessor的處理,不但要實(shí)現(xiàn)注冊功能,而且還要實(shí)現(xiàn)對(duì)后處理器的激活操作,所以需要載入配置中的定義,并進(jìn)行激活;而對(duì)于BeanPostProcessor并不需要馬上調(diào)用,再說,硬編碼的方式實(shí)現(xiàn)的功能是將后處理器提取并調(diào)用,這里并不需要調(diào)用,當(dāng)然不需要考慮硬編碼的方式了,這里的功能只需要將配置文件的BeanPostProcessor提取出來并注冊進(jìn)入beanFactory就可以了。

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

初始化消息資源

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

在initMessageSource中獲取自定義資源文件的方式為beanFactory.getBean(MESSAGE_ SOURCE_BEAN_NAME, MessageSource.class),在這里Spring使用了硬編碼的方式硬性規(guī)定了子定義資源文件必須為message,否則便會(huì)獲取不到自定義資源配置。

 protected void initMessageSource() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        //messageSource
        if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
            //如果在配置中已經(jīng)配置了messageSource,那么將messageSource提取并記錄在this.messageSource中
            this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
            if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
                HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
                if (hms.getParentMessageSource() == null) {
                    hms.setParentMessageSource(getInternalParentMessageSource());
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Using MessageSource [" + this.messageSource + "]");
            }
        }
        else {
            //如果用戶并沒有定義配置文件,那么使用臨時(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 + "]");
            }
        }
    }

初始化ApplicationEventMulticaster

initApplicationEventMulticaster的方式比較簡單,無非考慮兩種情況:

如果用戶自定義了事件廣播器,那么使用用戶自定義的事件廣播器。

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

protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        //applicationEventMulticaster
        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)聽器并在合適的時(shí)候調(diào)用監(jiān)聽器,那么進(jìn)入默認(rèn)的廣播器實(shí)現(xiàn)SimpleApplicationEventMulticaster來一探究竟。

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

protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
   ErrorHandler errorHandler = getErrorHandler();
   if (errorHandler != null) {
      try {
         listener.onApplicationEvent(event);
      }
      catch (Throwable err) {
         errorHandler.handleError(err);
      }
   }
   else {
      listener.onApplicationEvent(event);
   }
}

可以推斷,當(dāng)產(chǎn)生Spring事件發(fā)生的時(shí)候會(huì)默認(rèn)使用SimpleApplicationEventMulticaster的multicastEvent來廣播事件,遍歷所有監(jiān)聽器,并使用監(jiān)聽器中的onApplicationEvent方法來進(jìn)行監(jiān)聽器的處理。而對(duì)于每個(gè)監(jiān)聽器來說其實(shí)都可以獲取到產(chǎn)生的事件,但是是否進(jìn)行處理則由事件監(jiān)聽器來決定。

注冊監(jiān)聽器

 protected void registerListeners() {
        //硬編碼方式注冊的監(jiān)聽器處理
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }
        //配置文件注冊的監(jiān)聽器處理
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }
        
     //廣播早期的事件進(jìn)行廣播和事件處理
     // 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);
            }
        }
    }

初始化非延遲加載單例

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

 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        //conversionService的bean會(huì)被注冊
        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));
        }
        // 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定義,說明注冊的bean定義將不被修改或任何進(jìn)一步的處理。
        beanFactory.freezeConfiguration();
        //初始化剩下的單實(shí)例(非惰性的)
        beanFactory.preInstantiateSingletons();
    }

ConversionService的設(shè)置,之前我們提到過使用自定義類型轉(zhuǎn)換器從String轉(zhuǎn)換為Date的方式,使用屬性編輯器,那么,在Spring中還提供了另一種轉(zhuǎn)換方式:使用Converter。

ApplicationContext實(shí)現(xiàn)的默認(rèn)行為就是在啟動(dòng)時(shí)將所有單例bean提前進(jìn)行實(shí)例化。提前實(shí)例化意味著作為初始化過程的一部分,ApplicationContext實(shí)例會(huì)創(chuàng)建并配置所有的單例bean。通常情況下這是一件好事,因?yàn)檫@樣在配置中的任何錯(cuò)誤就會(huì)即刻被發(fā)現(xiàn)(否則的話可能要花幾個(gè)小時(shí)甚至幾天)。而這個(gè)實(shí)例化的過程就是在finishBeanFactoryInitialization中完成的,詳細(xì)流程見Spring框架的設(shè)計(jì)理念章節(jié)。

finishRefresh

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

 protected void finishRefresh() {
        // Initialize lifecycle processor for this context.
        //lifecycleProcessor的bean會(huì)被注冊
     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);
    }

initLifecycleProcessor

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

onRefresh

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

publishEvent

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

原文鏈接:https://www.cnblogs.com/wade-luffy/p/6072460.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,310評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,951評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,566評(píng)論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,055評(píng)論 1 322
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,303評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,799評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,683評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,899評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,135評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評(píng)論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,528評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,844評(píng)論 2 372

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