ApplicationContext做爲資源加載器;ApplicationContext做爲事件發佈者;java
Java原生提供了事件發佈機制------EventObject對象做爲發佈的事件,EventListener做爲處理髮布事件的監聽器。可是其並無提供發佈者的角色來橋接EventObject和EventListener。Spring對java原生的事件發佈機制作了擴展:一方面擴展了EventObject和EventListener,使其能夠記錄事件發佈時間,擴展了事件發佈接口;更重要的一點,ApplicationContext自身能夠充當事件發佈者(由於其實現了ApplicationEventPublisher接口),完成了本應該由開發者來實現的代碼(若是使用java原生髮布事件機制的話)。當對象A(被觀察者)發生變化時,有一個發佈者(能夠是被觀察者自身,也能夠委託第三方如spring容器)發出通知,事物B(觀察者)可以收到通知更新本身的狀態。這個就是常常使用到的觀察者模式,spring容器提供了這種觀察者模式的支持。咱們經過一個例子來講明如何在Spring框架中使用事件發佈,並能讓觀察者(listener)獲得消息。首先,自定義咱們的EventObject,做爲發佈者和監聽者之間約定好的事件對象。spring
public class MyEvent extends ApplicationEvent { /** * */ private static final long serialVersionUID = 1L; /** * @param source */ public MyEvent(Object source){ super(source); // TODO Auto-generated constructor stub } }
自定義的MyEvent繼承了ApplicationEvent,ApplicationEvent類是spring框架繼承EventObject而來,加入了獲取發佈時間的方法。其次,自定義咱們的EventListener,它負責監聽容器發佈的ApplicationEvent事件並進行處理:app
public class MyListener implements ApplicationListener { /* (non-Javadoc) * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) */ @Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof MyEvent) { System.out.println(event == null ? "" : event.getSource()); } } }
由於咱們只關心MyEvent事件的發佈,因此在onApplicationEvent方法中進行了判斷,過濾其餘不相關發佈事件。定義完了事件和監聽器,基本就剩下發布事件的代碼了。發佈者由ApplicationContext來充當:框架
public class TestPublisher { public static void main ( String args[] ) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); // applicationContext.xml配置文件中已經配置好了監聽器 ctx.publishEvent(new MyEvent("Hello World")); // 發佈事件,監聽器接收到事件消息 } }
最後,不要忘記在配置文件中添加監聽對象:ide
<bean class="com.alibaba.china.publisher.MyListener" />
spring容器會自動加載配置文件中全部的ApplicationListener對象,把它註冊到觀察者列表中。當有事件發佈的時候,就從這個觀察者列表中挨個通知事件發佈。程序執行結果以下: post
其餘細節點:spa
ApplicationContext自動加載全部的Bean:ApplicationContext相對於BeanFactory不一樣的一點是,BeanFactory在用到Bean的時候纔會去加載bean(在beanFactory.getBean(「beanName」)以前不會加載beanName的對象)。而ApplicationContext不一樣,在容器建立時就已經把全部的Bean加載進容器了。code
ApplicationContext自動識別BeanFactoryPostProcessor,BeanPostProcessor,並註冊到容器中:BeanFactoryPostProcessor是容器在加載完BeanDefinition以後,容器初始化以前對beanFactory作處理的一個擴展機制。好比咱們的antx配置項替換類PropertyPlaceholderConfigurer。咱們只須要在配置文件中聲明PropertyPlaceholderConfigurer這類BeanFactoryPostProcessor對象,ApplicationContext就可以識別出來並自動將這些processor註冊到容器中。BeanPostProcessor也是一樣的道理,ApplicationContext可以自動識別xml中配置好的這類bean並進行容器的註冊。BeanFactory就不能這麼簡潔了,必須咱們手動去把那些BeanFactoryPostProcessor以及BeanPostProcessor對象註冊到容器中。ApplicationContext可以本身感知到這些processor,咱們的工做只是去實現自定義的(或者直接使用spring已經實現了的)BeanFactoryPostProcessor和BeanPostProcessor,並在配置文件中聲明。是否是以爲很神奇?ApplicationContext能作到感知的緣由就在於其對mdb(Merged BeanDefinition)的處理。xml
org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory)實現: // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the bean factory post-processors apply to them! // beanFactory的getBeanNamesForType方法可以根據對象的類型(此處是BeanFactoryPostProcessor.class),從mdb中找到他們的beanName String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); ...... // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered. Collections.sort(priorityOrderedPostProcessors, new OrderComparator()); // 這裏全部聲明在配置文件中的BeanFactoryPostProcessor都被調用,執行接口的postProcessBeanFactory方法。 invokeBeanFactoryPostProcessors(beanFactory, priorityOrderedPostProcessors);
上面的代碼中會從mdb中找出BeanFactoryPostProcessor接口的對象,並對它們進行排序,而後根據這些BeanFactoryPostProcessor依次對beanFactory處理。對象