ClassPathXmlApplicationContext的啟動


Spring將ApplicationContext啟動的全過程,refresh函數中包含了幾乎ApplicationContext中提供的全部功能,而且此函數中邏輯非常清晰明了,很容易分析對應的層次及邏輯。:

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

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

環境准備

    protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);
        if (logger.isInfoEnabled()) {
            logger.info("Refreshing " + this);
        }
        //留給子類覆蓋
        initPropertySources();
        //驗證需要的屬性文件是否都已經放入環境中
        getEnvironment().validateRequiredProperties();
     //to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
    }

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

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

我們自定義了繼承自ClassPathXmlApplicationContext的MyClassPathXmlApplicationContext,並重寫了initPropertySources方法,在方法中添加了我們的個性化需求,那么在驗證的時候也就是程序走到getEnvironment().validateRequiredProperties()代碼的時候,如果系統並沒有檢測到對應classpath的環境變量,那么將拋出異常。

加載BeanFactory

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        //初始化BeanFactory,並進行XML文件讀取,並將得到的BeanFacotry記錄在當前實體的屬性中
        refreshBeanFactory();
        //返回當前實體的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的時候,聲明方式為:BeanFactory bf = new XmlBeanFactory("beanFactoryTest.xml"),
       //其中的XmlBeanFactory繼承自DefaultListableBeanFactory,並提供了XmlBeanDefinitionReader類型的reader屬性,
       //也就是說DefaultListableBean Factory是容器的基礎。必須首先要實例化,那么在這里就是實例化DefaultListableBeanFactory的步驟。
DefaultListableBeanFactory beanFactory = createBeanFactory(); //為了序列化指定id,如果需要的話,讓這個BeanFactory從id反序列化到BeanFactory對象 beanFactory.setSerializationId(getId()); //定制beanFactory,設置相關屬性,包括是否允許覆蓋同名稱的不同定義的對象以及循環依賴以及 customizeBeanFactory(beanFactory); //初始化DodumentReader,並進行XML文件讀取及解析 loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { //使用全局變量記錄BeanFactory類實例。 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不為空,設置給beanFactory對象相應屬性, //此屬性的含義:是否允許覆蓋同名稱的不同定義的對象 if (this.allowBeanDefinitionOverriding != null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } //如果屬性allowCircularReferences不為空,設置給beanFactory對象相應屬性, //此屬性的含義:是否允許bean之間存在循環依賴 if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences); } } @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { //為指定beanFactory創建XmlBeanDefinitionReader XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); //對beanDefinitionReader進行環境變量的設置 beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); //對BeanDefinitionReader進行設置,可以覆蓋 initBeanDefinitionReader(beanDefinitionReader); //使用XmlBeanDefinitionReader的loadBeanDefinitions方法進行配置文件的加載及注冊 loadBeanDefinitions(beanDefinitionReader); }

功能擴展

    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        //設置beanFactory的classLoader為當前context的classLoader
        beanFactory.setBeanClassLoader(getClassLoader());
        //設置beanFactory的表達式語言處理器,Spring3增加了表達式語言的支持,SPEL語言。
        //默認可以使用#{bean.xxx}的形式來調用相關屬性值。
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        //為beanFactory增加了一個默認的propertyEditor,這個主要是對bean的屬性等設置管理的一個工具
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

        //添加BeanPostProcessor
        //ApplicationContextAwareProcessor實現了BeanPostProcessor接口,在bean實例化的時候會被調用
        //postProcessBeforeInitialization方法中調用了invokeAwareInterfaces。從invokeAwareInterfaces方法中,
     //我們可以看出來,實現這些Aware接口的bean在被初始化之后,可以取得一些對應的資源。
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //Spring將ApplicationContextAwareProcessor注冊后,在invokeAwareInterfaces方法中間調用的Aware類已經不是普通的bean了, //如ResourceLoaderAware,ApplicationEventPublisherAware等,需要在Spring做bean的依賴注入的時候忽略它們。 beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); beanFactory.ignoreDependencyInterface(EnvironmentAware.class); //設置了幾個自動裝配的特殊規則 //當注冊了依賴解析后,例如當注冊了對BeanFactory.class的解析后,當bean的屬性注入的時候,
     //一旦檢測到屬性為BeanFactory類型便會將beanFactory的實例注入進去。
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); //增加對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())); } //將相關環境變量及屬性注冊以單例模式注冊,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的調用時機,就是AbstractBeanFactory類中的initBeanWrapper方法,這是在bean初始化時使用的一個方法,主要是在將BeanDefinition轉換為BeanWrapper后用於對屬性的填充。在bean的初始化后會調用ResourceEditorRegistrar的registerCustomEditors方法進行批量的通用屬性編輯器注冊。注冊后,在屬性填充的環節便可以直接讓Spring使用這些編輯器進行屬性的解析了。
Spring中用於封裝bean的是BeanWrapper類型,而它又間接繼承了PropertyEditorRegistry類型,也就是我們之前反復看到的方法參數PropertyEditorRegistry,其實大部分情況下都是BeanWrapper,對於BeanWrapper在Spring中的默認實現是BeanWrapperImpl,而BeanWrapperImpl除了實現BeanWrapper接口外還繼承了PropertyEditorRegistrySupport,在PropertyEditorRegistrySupport中有這樣一個方法:createDefaultEditors,基本的屬性編輯器就在此處被注冊。

BeanFactory的后處理

BeanFactoryPostProcessor接口跟BeanPostProcessor類似,可以對bean的定義(配置元數據)進行處理。也就是說,Spring IoC容器允許BeanFactoryPostProcessor在容器實際實例化任何其他的bean之前讀取配置元數據,並有可能修改它。如果你願意,你可以配置多個BeanFactoryPostProcessor。你還能通過設置“order”屬性來控制BeanFactoryPostProcessor的執行次序(僅當BeanFactoryPostProcessor實現了Ordered接口時你才可以設置此屬性,因此在實現BeanFactoryPostProcessor時,就應當考慮實現Ordered接口)。

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

在Spring中存在對於BeanFactoryPostProcessor的兩種典型應用。

(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是個bean工廠后置處理器的實現,也就是BeanFactoryPostProcessor接口的一個實現。PropertyPlaceholderConfigurer可以將上下文(配置文件)中的屬性值放在另一個單獨的標准java Properties文件中去。在XML文件中用${key}替換指定的properties文件中的值。這樣的話,只需要對properties文件進行修改,而不用對xml配置文件進行修改。
在Spring中,使用PropertyPlaceholderConfigurer可以在XML配置文件中加入外部屬性文件,當然也可以指定外部文件的編碼,PropertyPlaceholderConfigurer如果在指定的Properties文件中找不到你想使用的屬性,它還會在Java的System類屬性中查找。可以通過System.setProperty(key, value)或者java中通過-Dnamevalue來給Spring配置文件傳遞參數。

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

(2)使用自定義BeanFactoryPostProcessor 

實現一個BeanFactoryPostProcessor,實現一個簡單的回調處理器,它能去除潛在的"流氓"屬性值,例如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的方法中我們看到,對於BeanFactoryPostProcessor的處理主要分兩種情況進行,一個是對於BeanDefinitionRegistry類的特殊處理,另一種是對普通的BeanFactoryPostProcessor進行處理。而對於每種情況都需要考慮硬編碼注入注冊的后處理器以及通過配置注入的后處理器

對於硬編碼注冊的后處理器的處理,主要是通過AbstractApplicationContext中的添加處理器方法addBeanFactoryPostProcessor進行添加。

public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {

this.beanFactoryPostProcessors.add(beanFactoryPostProcessor);

}

添加后的后處理器會存放在beanFactoryPostProcessors中,而在處理BeanFactoryPostProcessor時候會首先檢測beanFactoryPostProcessors是否有數據。當然,BeanDefinitionRegistryPostProcessor繼承自BeanFactoryPostProcessor,不但有BeanFactoryPostProcessor的特性,同時還有自己定義的個性化方法,也需要在此調用。所以,這里需要從beanFactoryPostProcessors中挑出BeanDefinitionRegistryPostProcessor的后處理器,並進行其postProcessBeanDefinitionRegistry方法的激活。

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

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

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

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

(3)對以上所記錄的List中的后處理器進行統一調用BeanFactoryPostProcessor的postProcessBeanFactory方法。

(4)對beanFactoryPostProcessors中非BeanDefinitionRegistryPostProcessor類型的后處理器進行統一的BeanFactoryPostProcessor的postProcessBeanFactory方法調用。

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

對於硬編碼方式手動添加的后處理器是不需要做任何排序的,但是在配置文件中讀取的處理器,Spring並不保證讀取的順序。所以,為了保證用戶的調用順序的要求,Spring對於后處理器的調用支持按照PriorityOrdered或者Ordered的順序調用。

注冊BeanPostProcessor

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

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

對於beanFactory的注冊,也不是直接注冊就可以的。在Spring中支持對於BeanPostProcessor的排序,比如根據PriorityOrdered進行排序、根據Ordered進行排序或者無序,而Spring在BeanPostProcessor的激活順序的時候也會考慮對於順序的問題而先進行排序。

初始化消息資源

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

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

    protected void initMessageSource() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        //messageSource
        if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
            //如果在配置中已經配置了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 {
            //如果用戶並沒有定義配置文件,那么使用臨時的DelegatingMessageSource以便於作為調用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的方式比較簡單,無非考慮兩種情況:

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

如果用戶沒有自定義事件廣播器,那么使用默認的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 + "]");
            }
        }
    }

按照之前介紹的順序及邏輯,作為廣播器,一定是用於存放監聽器並在合適的時候調用監聽器,那么進入默認的廣播器實現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);
   }
}

可以推斷,當產生Spring事件發生的時候會默認使用SimpleApplicationEventMulticaster的multicastEvent來廣播事件,遍歷所有監聽器,並使用監聽器中的onApplicationEvent方法來進行監聽器的處理。而對於每個監聽器來說其實都可以獲取到產生的事件,但是是否進行處理則由事件監聽器來決定。

注冊監聽器

    protected void registerListeners() {
        //硬編碼方式注冊的監聽器處理
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }
        //配置文件注冊的監聽器處理
        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); } } }

初始化非延遲加載單例

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

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

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

ApplicationContext實現的默認行為就是在啟動時將所有單例bean提前進行實例化。提前實例化意味着作為初始化過程的一部分,ApplicationContext實例會創建並配置所有的單例bean。通常情況下這是一件好事,因為這樣在配置中的任何錯誤就會即刻被發現(否則的話可能要花幾個小時甚至幾天)。而這個實例化的過程就是在finishBeanFactoryInitialization中完成的,詳細流程見Spring框架的設計理念章節。

finishRefresh

在Spring中還提供了Lifecycle接口,Lifecycle中包含start/stop方法,實現此接口后Spring保證在啟動的時候調用其start方法開始生命周期,並在Spring關閉的時候調用stop方法來結束生命周期,通常用來配置后台程序,在啟動后一直運行(如對MQ進行輪詢等)。而ApplicationContext的初始化最后正是保證了這一功能的實現。

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

當ApplicationContext啟動或停止時,它會通過LifecycleProcessor來與所有聲明的bean周期做狀態更新,而在LifecycleProcessor的使用前首先需要初始化。

onRefresh

啟動所有實現了Lifecycle接口的bean。

publishEvent

當完成ApplicationContext初始化的時候,要通過Spring中的事件發布機制來發出ContextRefreshedEvent事件,以保證對應的監聽器可以做進一步的邏輯處理。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM