版權聲明:本文為博主原創文章,未經博主允許不得轉載。
ApplicationContext容器提供了容器內部事件發布功能,是繼承自JavaSE標准自定義事件類而實現的。
JavaSE標准自定義事件結構不在此詳細描述,一張圖很直觀的描述清楚:

EventObject,為JavaSE提供的事件類型基類,任何自定義的事件都繼承自該類,例如上圖中右側灰色的各個事件。Spring中提供了該接口的子類ApplicationEvent。
EventListener為JavaSE提供的事件監聽者接口,任何自定義的事件監聽者都實現了該接口,如上圖左側的各個事件監聽者。Spring中提供了該接口的子類ApplicationListener接口。
JavaSE中未提供事件發布者這一角色類,由各個應用程序自行實現事件發布者這一角色。Spring中提供了ApplicationEventPublisher接口作為事件發布者,並且ApplicationContext實現了這個接口,擔當起了事件發布者這一角色。但ApplicationContext在具體實現上有所差異,Spring提供了ApplicationEventMulticaster接口,負責管理ApplicationListener和發布ApplicationEvent。ApplicationContext會把相應的事件相關工作委派給ApplicationEventMulticaster接口實現類來做。類圖如下所示:
事件發布時序圖如下:
Spring中提供一些Aware相關的接口,BeanFactoryAware、 ApplicationContextAware、ResourceLoaderAware、ServletContextAware等等,其中最常用到的是ApplicationContextAware。實現ApplicationContextAware的Bean,在Bean被初始后,將會被注入ApplicationContext的實例。ApplicationContextAware提供了publishEvent()方法,實現Observer(觀察者)設計模式的事件傳播機,提供了針對Bean的事件傳播功能。通過Application.publishEvent方法,我們可以將事件通知系統內所有的ApplicationListener。
Spring事件處理一般過程:
◆定義Event類,繼承org.springframework.context.ApplicationEvent。
◆編寫發布事件類Publisher,實現org.springframework.context.ApplicationContextAware接口。
◆覆蓋方法setApplicationContext(ApplicationContext applicationContext)和發布方法publish(Object obj)。
◆定義時間監聽類EventListener,實現ApplicationListener接口,實現方法onApplicationEvent(ApplicationEvent event)。
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; /** * * @author zq * */ public class HelloWorld implements ApplicationEventPublisherAware{ private String word; private ApplicationEventPublisher tradeEventPublisher; public void setWord(String w){ this.word = w; } public void say(){ System.out.println("say : "+ this.word); //construct a TradeEvent instance and publish it TradeEvent tradeEvent = new TradeEvent(new String("tradeEvent")); this.tradeEventPublisher.publishEvent(tradeEvent); } @Override public void setApplicationEventPublisher( ApplicationEventPublisher applicationEventPublisher) { // TODO Auto-generated method stub this.tradeEventPublisher = applicationEventPublisher; } }
2.接受事件import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextStartedEvent; public class TradeContextListener implements ApplicationListener{ @Override public void onApplicationEvent(ApplicationEvent e) { System.out.println(e.getClass().toString()); // TODO Auto-generated method stub if (e instanceof ContextStartedEvent){ System.out.println("it was contextStartedEvent"); } if (e instanceof TradeEvent){ System.out.println(e.getSource()); } } }
3配置文件<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean name="helloWorld" class="study.HelloWorld"> <property name="word" value="hello world"/> </bean> <bean id="tradeContextListener" class="study.TradeContextListener"/> </beans>
4.測試代碼import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import study.HelloWorld; public class TestHelloWorld { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub ApplicationContext applicationContext = new ClassPathXmlApplicationContext("study-context.xml"); HelloWorld bean = (HelloWorld)applicationContext.getBean("helloWorld"); bean.say(); } }
1) ContextRefreshedEvent:當ApplicationContext初始化或者刷新時觸發該事件。
2) ContextClosedEvent:當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的所有單例Bean都被銷毀。
3) RequestHandleEvent:在Web應用中,當一個http請求(request)結束觸發該事件。
ContestStartedEvent:Spring2.5新增的事件,當容器調用ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發該事件。
5) ContestStopedEvent:Spring2.5新增的事件,當容器調用ConfigurableApplicationContext的Stop()方法停止容器時觸發該事件。
下面通過一個例子展示如何處理Spring內定的事件(例程3.8)。創建一個Java工程,添加Spring開發能力后,新建ioc.test包。在包中新建ApplicationEventListener類,實現ApplicationListener接口,在onApplicationEvent()方法中添加事件處理代碼,如下:
2
3 //Import省略
4 publicclass ApplicationEventListenerimplements ApplicationListener {
5
6 publicvoid onApplicationEvent(ApplicationEvent event) {
7
8 //如果是容器刷新事件
9 if(eventinstanceof ContextClosedEvent ){
10 System.out.println(event.getClass().getSimpleName()+" 事件已發生!");
11 }elseif(eventinstanceof ContextRefreshedEvent ){//如果是容器關閉事件
12 System.out.println(event.getClass().getSimpleName()+" 事件已發生!");
13 }elseif(eventinstanceof ContextStartedEvent ){
14 System.out.println(event.getClass().getSimpleName()+" 事件已發生!");
15 }elseif(eventinstanceof ContextStoppedEvent){
16 System.out.println(event.getClass().getSimpleName()+" 事件已發生!");
17 }else{
18 System.out.println("有其它事件發生:"+event.getClass().getName());
19 }
20
21 }
22
23 }
24
在Spring配置文件中定義一個Bean,類為ApplicationEventListener,代碼如下:
2 <beans…………
3
4 <bean id="ApplicationEventListener" class="ioc.test.ApplicationEventListener"/>
5
6 </beans>
7
添加含有主方法的TesMain類,在主方法中,調用容器的相應方法,觸發Spring內定事件,代碼如下:
2
3 //import省略
4 publicclass TesMain {
5
6 publicstaticvoid main(String[] args) {
7 AbstractApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
8
9
10 // ac.refresh();//觸發ContextRefreshedEvent事件
11 ac.start();//觸發ContextStartedEvent事件
12 ac.stop(); //觸發ContextStoppedEvent事件
13 ac.close();//關閉容器,觸發ContextClosedEvent事件
14
15 }
16 }
17
運行主類,控制台輸出如下:
從例子中可以知道,要注冊事件監聽器,我們只需要把它配置成一個Bean即可,ApplicationContext容器會自動將其注冊。

