假若有一個文件位於Web應用的類路徑下,用戶能夠經過如下方式對這個文件資源進行訪問:java
經過FileSystemResource
以文件系統絕對路徑的方式進行訪問;web
經過ClassPathResource
以類路徑的方式進行訪問;spring
經過ServletContextResource
以相對於Web應用根目錄的方式進行訪問。緩存
BeanFactory
:位於類結構樹的頂端,最主要的方法是getBean(String beanName)
,從容器中返回特定類型的beanapp
ListableBeanFactory
:該接口定義了訪問容器中Bean基本信息的若干方法異步
HierarchicalBeanFactory
:父子級聯IoC容器的接口,子容器能夠經過接口方法訪問父容器編輯器
ConfigurableBeanFactory
:加強了IoC容器的可定製性ide
AutowireCapableBeanFactory
:定義了將容器中的bean按照某種規則進行自動裝配的方法函數
SingletonBeanRegistry
:定義了容許在運行期向容器註冊單實例bean的方法post
BeanDefinitionRegistry
:每個bean在容器中經過BeanDefinition
對象表示,BeanDefinitionRegistry
定義了向容器手工註冊bean的方法
Spring在DefaultSingletonBeanRegistry
類中提供了一個用於緩存單實例bean的緩存器,以HashMap
實現,單實例的bean以beanName
爲key保存在這個HashMap
中
ApplicationEventPublisher
:讓容器擁有發佈應用上下文事件的功能,包括容器啓動事件、關閉事件等。實現了ApplicationListener
事件監聽接口的Bean 能夠接收到容器事件,並對事件進行響應處理。在ApplicationContext
抽象實現類AbstractApplicationContext
中,咱們能夠發現存在一個ApplicationEventMulticaster
,它負責保存全部監聽器,以便在容器產生上下文事件時通知這些事件監聽者。
MessageSource
:爲應用提供i18n國際化消息訪問的功能;
ResourcePatternResolver
:全部ApplicationContext
實現類都實現了相似於PathMatchingResourcePatternResolver
的功能,能夠經過帶前綴的Ant風格的資源文件路徑裝載Spring的配置文件。
LifeCycle
:該接口是Spring 2.0加入的,該接口提供了start()
和stop()
兩個方法,主要用於控制異步處理過程。在具體使用時,該接口同時被ApplicationContext
實現及具體Bean實現,ApplicationContext
會將start/stop
的信息傳遞給容器中全部實現了該接口的Bean,以達到管理和控制JMX、任務調度等目的。
ConfigurableApplicationContext
擴展於ApplicationContext
,它新增長了兩個主要的方法:refresh()
和close()
,讓ApplicationContext
具備啓動、刷新和關閉應用上下文的能力。在應用上下文關閉的狀況下調用refresh()
便可啓動應用上下文,在已經啓動的狀態下,調用refresh()
則清除緩存並從新裝載配置信息,而調用close()
則可關閉應用上下文。
它容許從相對於Web根目錄的路徑中加載配置文件完成初始化工做。從WebApplicationContext
中能夠獲取ServletContext
引用,整個Web應用上下文對象將做爲屬性放置在ServletContext
中,以便Web應用環境能夠訪問spring上下文。
WebApplicationContext
擴展了ApplicationContext
,WebApplicationContext
定義了一個常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
,在上下文啓動時,咱們能夠直接經過下面的語句從web容器中獲取WebApplicationContext
:
WebApplicationContext wac=(WebApplicationContext)servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
若是容器註冊InstantiationAwareBeanPostProcessor
接口,調用postProcessBeforeInstantiation
方法
Bean的實例化(調用默認構造器)
若是容器註冊InstantiationAwareBeanPostProcessor
接口,調用postProcessAfterInstantiation
方法
若是容器註冊InstantiationAwareBeanPostProcessor
接口,調用postProcessPropertyValues
方法
根據配置設置屬性值
若是Bean實現了BeanNameAware
接口,調用BeanNameAware
接口的setBeanName
方法
若是Bean實現了BeanFactoryAware
接口,調用BeanFactoryAware
接口的setBeanFactory
方法
若是容器註冊了BeanPostProcessor
接口,調用BeanPostProcessor
接口的postProcessBeforeInitialization
方法
若是Bean實現了InitializingBean
接口,調用InitializingBean
接口的afterPropertiesSet
方法
經過init-method
屬性配置的初始方法
若是容器註冊了BeanPostProcessor
接口,調用BeanPostProcessor
接口的postProcessAfterInitialization
方法
若是是單例模式,將Bean放入緩存池中;容器銷燬時,調用DisposableBean的destroy
方法;最後調用destroy-method
方法
若是是多例模式,將Bean交給調用者。
bean自身的方法:如調用bean構造函數實例化bean,調用Setter
設置bean的屬性值,以及經過<bean>
的init-method
和destory-method
所指定的方法;
bean級生命週期接口方法:如BeanNameAware
、BeanFactoryAware
、InitializingBean
和DisposableBean
,這些接口方法由bean類直接實現;
容器級生命週期接口方法:如InstantiationAwareBeanPostProcessor
和 BeanPostProcessor
這兩個接口實現,通常稱它們的實現類爲「後處理器」。
Spring的AOP等功能即經過BeanPostProcessor
實現
若是<bean>
經過init-method
屬性定義了初始化方法,將執行這個方法
若是bean的做用範圍爲scope="prototype"
,將bean返回給調用者以後,調用者負責bean的後續生命的管理,Spring再也不管理這個bean的生命週期;若是scope="singleton"
,則將bean放入到Spring IoC容器的緩存池中,並將bean的引用返回給調用者,Spring繼續管理這些bean的後續生命週期
對於單例的bean,當容器關閉時,將觸發Spring對bean的後續生命週期的管理工做。若是bean實現了DisposableBean
接口,則將調用接口的destroy()
方法
對於單例的bean,若是經過destroy-method
指定了bean的銷燬方法,Spring將執行這個方法
後處理器的實際調用順序和註冊順序無關,在具備多個後處理器的狀況下,必須經過實現org.springframework.core.Ordered
接口肯定調用順序
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="car" class="com.data.Car" p:color="color" init-method="init" destroy-method="destroy2" /> </beans>
Car
package com.data; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; public class Car implements BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean { public Car() { System.out.println("construct car"); } private String name; private String color; private BeanFactory beanFactory; private String beanName; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getColor() { return color; } public void setColor(String color) { this.color = color; System.out.println("set color=" + color); } @Override public void afterPropertiesSet() throws Exception { System.out.println("after properties set method"); } public void init() { System.out.println("init method"); } @Override public void destroy() { System.out.println("destroy method"); } public void destroy2() { System.out.println("my destroy method"); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("set bean factory"); this.beanFactory = beanFactory; } @Override public void setBeanName(String name) { System.out.println("set bean name"); this.beanName = name; } public BeanFactory getBeanFactory() { return beanFactory; } public String getBeanName() { return beanName; } }
MyBeanPostProcessor
package com.beanfactory; import java.beans.PropertyDescriptor; import org.springframework.beans.BeansException; import org.springframework.beans.PropertyValues; import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; public class MyBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter{ public MyBeanPostProcessor() { System.out.println("construct MyBeanPostProcessor"); } @Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { System.out.println("post process before instantiation"); return null; } @Override public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { System.out.println("post process after instantiation"); return true; } @Override public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { System.out.println("post process property values"); return pvs; } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("post process before initialization"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("post process after initialization"); return bean; } }
TestBeanFactory
package config; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import com.beanfactory.MyBeanPostProcessor; import com.data.Car; @SuppressWarnings("deprecation") public class TestBeanFactory { public static void main(String[] args) { Resource res = new ClassPathResource( "/applicationContext.xml"); XmlBeanFactory bf = new XmlBeanFactory(res); bf.addBeanPostProcessor(new MyBeanPostProcessor()); System.out.println("bean factory initialization done"); Car car1 = bf.getBean("car", Car.class); Car car2 = bf.getBean("car", Car.class); System.out.println("(car1 == car2) = " + (car1 == car2)); System.out.println("get color=" + car1.getColor()); bf.destroySingletons(); } }
結果
二月 09, 2017 10:58:59 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [applicationContext.xml] construct MyBeanPostProcessor bean factory initialization done post process before instantiation construct car post process after instantiation post process property values set color=color set bean name set bean factory post process before initialization after properties set method init method post process after initialization (car1 == car2) = true get color=color destroy method my destroy method
若是bean實現了org.springframework.context.ApplicationContextAware
接口,會增長一個調用該接口方法setApplicationContext()
的步驟
若是配置文件中聲明瞭工廠後處理器接口BeanFactoryPostProcessor
的實現類,則應用上下文在加載配置文件以後、初始化bean實例以前將調用這些BeanFactoryPostProcessor
對配置信息進行加工處理
ApplicationContext
和BeanFactory
的不一樣之處在於:前者會利用Java反射機制自動識別出配置文件中定義的BeanPostProcessor
、InstantiationAwareBeanPostProcessor
和BeanFactoryPostProcessor
,並自動將它們註冊到應用上下文中;然後者須要在代碼中經過手工調用addBeanPostProcessor()
方法進行註冊
對bean的初始化,BeanFactory
發生在第一次調用bean時,而ApplicationContext
發生在初始化容器時
MyBeanPostProcessor
同上
Car
增長對ApplicationContextAware
接口的實現,並添加@PostConstruct
和@PreDestroy
的註解方法
package com.data; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class Car implements BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean, ApplicationContextAware { public Car() { System.out.println("construct car"); } private String name; private String color; private BeanFactory beanFactory; private String beanName; private ApplicationContext ctx; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } @Override public void afterPropertiesSet() throws Exception { System.out.println("after properties set method"); } public void init() { System.out.println("init method"); } @Override public void destroy() { System.out.println("destroy method"); } public void destroy2() { System.out.println("my destroy method"); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("set bean factory"); this.beanFactory = beanFactory; } @Override public void setBeanName(String name) { System.out.println("set bean name"); this.beanName = name; } public BeanFactory getBeanFactory() { return beanFactory; } public String getBeanName() { return beanName; } @PostConstruct public void postConstruct() { System.out.println("post construct"); } @PreDestroy public void preDestroy() { System.out.println("pre destroy"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("set application context"); this.ctx = applicationContext; } public ApplicationContext getApplicationContext() { return ctx; } }
MyBeanFactoryPostProcessor
package com.beanfactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { public MyBeanFactoryPostProcessor() { System.out.println("construct MyBeanFactoryPostProcessor"); } public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("post process bean factory"); } }
基於Java類的Spring配置:AnnotationBeans
package config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.beanfactory.MyBeanFactoryPostProcessor; import com.beanfactory.MyBeanPostProcessor; import com.data.Car; @Configuration public class AnnotationBeans { @Bean(name = "car", initMethod = "init", destroyMethod = "destroy2") public Car getCar() { Car car = new Car(); car.setColor("color"); return car; } @Bean(name = "myBeanPostProcessor") public MyBeanPostProcessor getMyBeanPostProcessor() { return new MyBeanPostProcessor(); } @Bean(name = "myBeanFactoryPostProcessor") public MyBeanFactoryPostProcessor getMyBeanFactoryPostProcessor() { return new MyBeanFactoryPostProcessor(); } }
TestApplicationContext
package config; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.data.Car; public class TestApplicationContext { public static void main(String[] args) { /*對於以xml形式初始化的ctx,也能夠用ClassPathXmlApplicationContext 或者FileSystemXmlApplicationContext*/ AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( AnnotationBeans.class); System.out.println("application context done"); Car car = ctx.getBean("car", Car.class); System.out.println("get color=" + car.getColor()); ctx.close(); } }
結果
二月 09, 2017 11:55:25 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@306a30c7: startup date [Thu Feb 09 23:55:25 CST 2017]; root of context hierarchy 二月 09, 2017 11:55:25 下午 org.springframework.context.annotation.ConfigurationClassEnhancer intercept 警告: @Bean method AnnotationBeans.getMyBeanFactoryPostProcessor is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean javadoc for complete details. construct MyBeanFactoryPostProcessor post process bean factory construct MyBeanPostProcessor post process before instantiation post process after instantiation post process property values post process before initialization post process after initialization post process before instantiation post process after instantiation post process property values post process before initialization post process after initialization post process before instantiation construct car post process after instantiation post process property values set bean name set bean factory set application context post process before initialization post construct after properties set method init method post process after initialization application context done get color=color 二月 09, 2017 11:55:25 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose 信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@306a30c7: startup date [Thu Feb 09 23:55:25 CST 2017]; root of context hierarchy pre destroy destroy method my destroy method
Spring的AbstractApplicationContext的refresh()
方法定義了Spring容器在加載配置文件後的各項處理工做
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. 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(); } } }
ContextLoaderListener
經過調用繼承自ContextLoader
的initWebApplicationContext
方法實例化SpringIoC容器。在實例化Spring IoC容器的過程當中,最主要的兩個方法是createWebApplicationContext
和configureAndRefreshWebApplicationContext方
法。createWebApplicationContext
方法用於返回XmlWebApplicationContext
實例,即Web環境下的SpringIoC容器。configureAndRefreshWebApplicationContext
用於配XmlWebApplicationContext
,讀取web.xml
中經過contextConfigLocation
標籤指定的XML文件,經過調用refresh
來調用AbstractApplicationContext
中的refresh
初始化。
BeanFactory
實例化XML文件中配置的bean,Spring將配置文件的bean的信息解析成爲一個個的BeanDefinition
對象並裝入到容器的Bean定義註冊表,但此時Bean還未初始化;obtainFreshBeanFactory()
會調用自身的refreshBeanFactory()
,而refreshBeanFactory()
方法由子類AbstractRefreshableApplicationContext
實現,該方法返回了一個建立的DefaultListableBeanFactory
對象,這個對象就是由ApplicationContext
管理的BeanFactory
容器對象;
調用工廠後處理器:根據反射機制從BeanDefinitionRegistry
中找出全部BeanFactoryPostProcessor
類型的Bean,並調用其postProcessBeanFactory()
接口方法。通過第一步加載配置文件,已經把配置文件中定義的全部bean裝載到BeanDefinitionRegistry
這個Beanfactory
中,對於ApplicationContext
應用來講這個BeanDefinitionRegistry
類型的BeanFactory
就是Spring默認的DefaultListableBeanFactory
註冊Bean後處理器:根據反射機制從BeanDefinitionRegistry
中找出全部BeanPostProcessor
類型的Bean,並將它們註冊到容器Bean後處理器的註冊表中;
初始化消息源:初始化容器的國際化信息資源;
初始化應用上下文事件廣播器;
初始化其餘特殊的Bean;
註冊事件監聽器;
初始化singleton的Bean:實例化全部singleton的Bean,並將它們放入Spring容器的緩存中;
發佈上下文刷新事件:在此處時容器已經啓動完成,發佈容器refresh
事件建立上下文刷新事件,事件廣播器負責將些事件廣播到每一個註冊的事件監聽器中。
ResourceLoader
從存儲介質中加載Spring配置文件,並使用Resource
表示這個配置文件的資源;
BeanDefinitionReader
讀取Resource
所指向的配置文件資源,而後解析配置文件。配置文件中每個<bean>
解析成一個BeanDefinition
對象,並保存到BeanDefinitionRegistry
中;
容器掃描BeanDefinitionRegistry
中的BeanDefinition
,使用Java的反射機制自動識別出Bean工廠後處理器(實現BeanFactoryPostProcessor
接口)的Bean,而後調用這些Bean工廠後處理器對BeanDefinitionRegistry
中的BeanDefinition
進行加工處理。主要完成如下兩項工做:
對使用到佔位符的<bean>
元素標籤進行解析,獲得最終的配置值,這意味對一些半成品式的BeanDefinition
對象進行加工處理並獲得成品的BeanDefinition
對象;
對BeanDefinitionRegistry
中的BeanDefinition
進行掃描,經過Java反射機制找出全部屬性編輯器的Bean(實現java.beans.PropertyEditor
接口的Bean),並自動將它們註冊到Spring容器的屬性編輯器註冊表中(PropertyEditorRegistry
);
Spring容器從BeanDefinitionRegistry
中取出加工後的BeanDefinition
,並調用InstantiationStrategy
着手進行Bean實例化的工做;
在實例化Bean時,Spring容器使用BeanWrapper
對Bean進行封裝,BeanWrapper
提供了不少以Java反射機制操做Bean的方法,它將結合該Bean的BeanDefinition
以及容器中屬性編輯器,完成Bean屬性的設置工做;
利用容器中註冊的Bean後處理器(實現BeanPostProcessor
接口的Bean)對已經完成屬性設置工做的Bean進行後續加工,直接裝配出一個準備就緒的Bean。
Spring事件體系包括三個組件:事件,事件監聽器,事件廣播器。
事件:ApplicationEvent
事件監聽器:ApplicationListener
,對監聽到的事件進行處理。
事件廣播器:ApplicationEventMulticaster
,將Spring publish的事件廣播給全部的監聽器。Spring在ApplicationContext
接口的抽象實現類AbstractApplicationContext
中完成了事件體系的搭建。
AbstractApplicationContext
擁有一個applicationEventMulticaster
成員變量,applicationEventMulticaster
提供了容器監聽器的註冊表。
private void initApplicationEventMulticaster() throws BeansException { if (containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME )) { this.applicationEventMulticaster = (ApplicationEventMulticaster) getBean( APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class ); if (logger.isInfoEnabled()) { logger.info("Using ApplicationEventMulticaster [" + this. applicationEventMulticaster + "]" ); } } else { this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(); if (logger.isInfoEnabled()) { logger.info("Unable to locate ApplicationEventMulticaster with name '"+ APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "': using default [" + this .applicationEventMulticaster + "]"); } } }
用戶能夠在配置文件中爲容器定義一個自定義的事件廣播器,只要實現ApplicationEventMulticaster
就能夠了,Spring會經過反射的機制將其註冊成容器的事件廣播器,若是沒有找到配置的外部事件廣播器,Spring自動使用 SimpleApplicationEventMulticaster
做爲事件廣播器。
private void registerListeners () throws BeansException { // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! Collection listeners = getBeansOfType(ApplicationListener.class,true,false).values(); for (Iterator it = listeners.iterator(); it.hasNext();) { addListener((ApplicationListener) it.next()); } } protected void addListener(ApplicationListener listener) { getApplicationEventMulticaster().addApplicationListener(listener); }
Spring根據反射機制,使用ListableBeanFactory
的getBeansOfType
方法,從BeanDefinitionRegistry
中找出全部實現 org.springframework.context.ApplicationListener
的Bean,將它們註冊爲容器的事件監聽器,實際的操做就是將其添加到事件廣播器所提供的監聽器註冊表中。
public void publishEvent(ApplicationEvent event) { Assert.notNull(event, "Event must not be null"); if (logger.isDebugEnabled()) { logger.debug("Publishing event in context [" + getDisplayName() + "]: " + event); } getApplicationEventMulticaster().multicastEvent(event); if (this.parent != null) { this.parent.publishEvent(event); } }
在AbstractApplicationContext
的publishEvent
方法中, Spring委託ApplicationEventMulticaster
將事件通知給全部的事件監聽器
public void multicastEvent( final ApplicationEvent event) { for (Iterator it = getApplicationListeners().iterator(); it.hasNext();) { final ApplicationListener listener = (ApplicationListener) it.next(); getTaskExecutor().execute(new Runnable() { public void run() { listener.onApplicationEvent(event); } }); } }
遍歷註冊的每一個監聽器,並啓動來調用每一個監聽器的onApplicationEvent
方法。
因爲SimpleApplicationEventMulticaster
的taskExecutor
的實現類是SyncTaskExecutor
,所以,事件監聽器對事件的處理,是同步進行的。
springEvent.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.event" /> </beans>
MockEvent
package com.event; import org.springframework.context.ApplicationContext; import org.springframework.context.event.ApplicationContextEvent; public class MockEvent extends ApplicationContextEvent { public MockEvent(ApplicationContext source) { super(source); } }
MockEventListener
package com.event; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; @Component public class MockEventListener implements ApplicationListener<MockEvent> { public void onApplicationEvent(MockEvent event) { System.out.println("mock event received"); } }
MockEventPublisher
package com.event; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component;; @Component public class MockEventPublisher implements ApplicationContextAware { private ApplicationContext ctx; public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.ctx = applicationContext; } public void publishEvent() { System.out.println("publish event"); MockEvent event = new MockEvent(this.ctx); ctx.publishEvent(event); } }
MockEventTest
package com.event; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MockEventTest { public static void main(String[] args) { ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext( "/springEvent.xml"); MockEventPublisher publisher = ctx.getBean(MockEventPublisher.class); publisher.publishEvent(); ctx.close(); } }
結果
二月 09, 2017 9:57:43 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@69d0a921: startup date [Thu Feb 09 21:57:43 CST 2017]; root of context hierarchy 二月 09, 2017 9:57:43 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [springEvent.xml] publish event mock event received 二月 09, 2017 9:57:44 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose 信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@69d0a921: startup date [Thu Feb 09 21:57:43 CST 2017]; root of context hierarchy