javascript
Spring的事件发布机制
一:Spring的事件發布
??? ApplicationContext提供了針對Bean的事件傳播功能,其中的主角是publishEvent()方法,通過這個方法可以將事件通知給系統內的監聽器(需實現ApplicationListener接口)。
??? ApplicationContext這個接口,是Spring的上下文,通常獲取Bean就需要這個接口,這個接口并不是直接繼承于BeanFactory,其中最著名的是直接繼承了ApplicationPublisher接口,這個接口查看源碼可以發現:只有一個方法,那就是主角 void publishEvent(ApplicationEvent event);
??? Spring提供的基于Aware相關的接口有ApplicationContextAware,ResourceloaderAware,ServletContextAware(注意:Struts2也有這個接口,注意區分),最常用的就這三個,而Spring的事件發布機制需要用到ApplicationContextAware接口。
??? 實現了ApplicationContextAware的Bean,在Bean初始化時將會被注入ApplicationContext實例(因為這個接口里有set(ApplictationContext ctx)方法)
二:有了以上基礎,看示例代碼:
1.首先創建事件類 TradeEvent
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | packagenet.wang.test; importorg.springframework.context.ApplicationEvent; /** ?* 事件Event ?* @author LiuRuoWang ?*/ publicclassTradeEvent extendsApplicationEvent{ ????? ????publicTradeEvent(Object source) { ????????super(source); ????????System.out.println("事件:TradeEvent event !!"); ????} ????? } 事件必須繼承Spring提供的ApplicationEvent抽象類 |
| 2.然后編寫 事件的發布者HelloWorld |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | packagenet.wang.test; importorg.springframework.context.ApplicationEventPublisher; importorg.springframework.context.ApplicationEventPublisherAware; /** ?* 事件的發布者 ?* @author LiuRuoWang ?*/ publicclassHelloWorld implementsApplicationEventPublisherAware{ ????? ????privateString word; ????? ????publicvoidsetWord(String word) { ????????this.word = word; ????} ????? ????privateApplicationEventPublisher tradeEventPublisher; ????? ????publicvoidsetApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { ????????this.tradeEventPublisher=applicationEventPublisher; ????} ????? ????publicvoidsay(){ ????????System.out.println("say:"+this.word); ????????TradeEvent tradeEvent = newTradeEvent(newString("HelloWorld!")); ????????this.tradeEventPublisher.publishEvent(tradeEvent); ????} ????? } |
| 1 | 其中在say()方法里發布了事件 |
| 1 | 3.最后編寫 事件的接收者EventReceiver: |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | packagenet.wang.test; importorg.springframework.context.ApplicationListener; /** ?* 事件的接收者 ?* @author LiuRuoWang ?*/ publicclassEventReceiver implementsApplicationListener<TradeEvent>{ ????publicvoidonApplicationEvent(TradeEvent event) { ????????System.out.println("監聽到的事件:"+event.getSource()); ????} } |
| 1 | 事件的接收者其實是一個監聽器,必須實現ApplicationListener,注意把事件TradeEvent直接寫到泛型中 |
| 1 | 4.applicationContext.xml: |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?xml version="1.0"encoding="GBK"?> <beans ????xmlns="http://www.springframework.org/schema/beans" ????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ????xmlns:p="http://www.springframework.org/schema/p" ????xmlns:aop="http://www.springframework.org/schema/aop" ????xmlns:tx="http://www.springframework.org/schema/tx" ????xsi:schemaLocation="http://www.springframework.org/schema/beans ????????http://www.springframework.org/schema/beans/spring-beans-3.1.xsd ????????http://www.springframework.org/schema/aop ????????http://www.springframework.org/schema/aop/spring-aop-3.1.xsd ????????http://www.springframework.org/schema/tx ????????http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> ????? ????<bean name="helloWrold"class="net.wang.test.HelloWorld"> ????????<property name="word"value="Word!"/> ????</bean> ????? ????<bean name="eventReceiver"class="net.wang.test.EventReceiver"/> ????? </beans> |
注意把事件的接收者寫入配置文件中
5.測試Test:
| 1 2 3 4 5 6 7 8 9 10 11 12 | packagenet.wang.test; importorg.springframework.context.ApplicationContext; importorg.springframework.context.support.ClassPathXmlApplicationContext; publicclassTest { ????publicstaticvoidmain(String[] args) { ????????ApplicationContext ctx=newClassPathXmlApplicationContext("applicationContext.xml"); ????????HelloWorld h = (HelloWorld) ctx.getBean("helloWrold"); ????????h.say(); ????} } |
6.結果顯示:
結果中已經顯示監聽到的事件,說明成功。
Spring 中的事件監聽的實現
這里我們不討論事件監聽的機制的原理,我們只討論如何在項目中實現時間監聽。?
Spring的事件監聽是基于觀察者模式。設計開發中。如下類與接口是我們必須要使用的。
ApplicationContext
首先我們了解一下ApplicationContext,還記得
ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");- 1
ApplicationContext相當于Spring的一個與IOC容器連接的橋梁,通過getBean();方法,我們可以輕松的從IOC容器中獲取Bean對象。?
因為ApplicationContext是實現ApplicationEventPublisher的。查看ApplicationEventPublisher的源碼,我們發現有一方法publishEvent。此方法便是發布事件的方法,即觸發事件的方法,通過調用publishEvent方法,注入事件ApplicationEvent的子類,實現事件的觸發。
- 1
- 2
- 1
- 2
- 3
- 4
- 5
- 6
說了一大堆,就是想說ApplicationContext的
publicEvent(ApplicationEvent event);
方法是可以用來發布通知,相當于觸發事件的事件源。
ApplicationContextAware
ApplicationContextAware類似于ServeletRequestAware,通過讓Action實現Aware,使得Action初始化之后便可以獲得一些資源,這里我們讓Action實現ApplicationContext,使得Action擁有ApplicationContext,Action中擁有ApplicationContext之后就可以調用publicEvent方法進行通知
public interface ApplicationContextAware extends Aware {void setApplicationContext(ApplicationContext applicationContext) throws BeansException;}- 1
- 2
- 3
- 4
ApplicationEvent
ApplicationEvent相當于一個事件,所有自定義事件都需要繼承這個抽象類。在Eclipse中Ctrl+Shift+H調用類的層次結構列表,可以看到如下?
?
Application下抽象子類ApplicationContextEvent的下面有4個已經實現好的事件?
ContextClosedEvent(容器關閉時)?
ContextRefreshedEvent(容器刷新是)?
ContextStartedEvent(容器啟動時候)?
ContextStoppedEvent(容器停止的時候)?
同樣,這四個事件都繼承了ApplicationEvent,如果我們想自定義事件,也可以通過繼承ApplicationEvent來實現?
嗯,同樣是一句話總結ApplicationEvent就是一個抽象類,創建時間的時候只需要繼承它就可以。
ApplicationListener
從名字可以看出來,這是一個監聽器。為什么需要監聽器呢?監聽器是用于接收事件,并觸發事件的操作,這樣說起來可能有點費解,簡單的說就是,Listener是監聽ApplicationContext.publishEvent,方法的調用,一旦調用publishEvent,就會執行ApplicaitonListener中的方法,下面這個是ApplicationContext的源碼。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {/*** publishEvent觸發該方方法* 可以在該方法中寫各種業務邏輯*/void onApplicationEvent(E event);}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
這里是實際代碼實現的過程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
2.新建一個監聽器MyListener
package cn.blueboz.elec.listener;import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.ContextStartedEvent; import org.springframework.context.event.ContextStoppedEvent; import org.springframework.stereotype.Service;import cn.blueboz.elec.event.HisEvent; import cn.blueboz.elec.event.MyEvent;//注入IOC容器中 @Service("myListener") public class MyListener implements ApplicationListener<ApplicationEvent> {//調用ApplicationContext.publishEvent方法時會觸發執行該方法@Overridepublic void onApplicationEvent(ApplicationEvent event) {//判斷事件為MyEvent時候執行if(event instanceof MyEvent){//強制轉換MyEvent evt=(MyEvent) event;//執行自定義事件中的自定義方法evt.myevent();}//如果容器關閉時,觸發if(event instanceof ContextClosedEvent){ContextClosedEvent cce=(ContextClosedEvent) event;System.out.println("#####################");System.out.println("容器關閉");System.out.println(cce);System.out.println("#####################");}//容器刷新時候觸發if(event instanceof ContextRefreshedEvent){ContextRefreshedEvent cre=(ContextRefreshedEvent) event;System.out.println("#####################");System.out.println("容器刷新");System.out.println(cre);System.out.println("#####################");}//容器啟動的時候觸發if(event instanceof ContextStartedEvent){ContextStartedEvent cse=(ContextStartedEvent) event;System.out.println("#####################");System.out.println("容器啟動");System.out.println(cse);System.out.println("#####################");}//容器停止時候觸發if(event instanceof ContextStoppedEvent){ContextStoppedEvent cse=(ContextStoppedEvent) event;System.out.println("#####################");System.out.println("容器停止");System.out.println(cse);System.out.println("#####################");}}}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
3.最后,我們要再Action中發布通知publishEvent;
package cn.blueboz.elec.web.action;import javax.annotation.Resource;import org.apache.struts2.interceptor.ServletRequestAware; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Scope; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Controller;import cn.blueboz.elec.domain.ElecText; import cn.blueboz.elec.event.MyEvent; import cn.blueboz.elec.service.IElecTextService;//指定為prototype原型,對應每一個請求都會產生一個實例對象 @Controller("elecTextAction") @Scope(value="prototype") public class ElecTextAction extends BaseAction<ElecText> implements ApplicationContextAware,ServletRequestAware {//首先獲得模型驅動對象ElecText elecText=getModel();protected ApplicationContext applicationContext;//注入Service指定從Spring的IOC容器中注入的對象的名稱@Resource(name=IElecTextService.SERVICE_NAME)private IElecTextService elecTextService;public String save(){//從表單中傳送過來的實例對象elecTextService.saveElecText(elecText);/*** 請關注這一行代碼,在頁面中訪問時候調用save方法* save方法中執行了publishEvent方法發布通知。* 傳入參數是自定義事件MyEvent*/applicationContext.publishEvent(new MyEvent("在Action中的save方法Public了Event"));return "save";}@Overridepublic void setApplicationContext(ApplicationContext applicationContext)throws BeansException {this.applicationContext=applicationContext;} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
4.啟動Tomcat時候命令行輸出
##################### 容器刷新 org.springframework.context.event.ContextRefreshedEvent[source=Root WebApplicationContext: startup date [Fri Nov 20 17:12:47 CST 2015]; root of context hierarchy] #####################- 1
- 2
- 3
- 4
訪問頁面的時候,命令行輸出,可以看出,觸發了MyEvent方法輸出。
********My event************** 在Action中的save方法Public了Event *******************************總結
以上是生活随笔為你收集整理的Spring的事件发布机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring boot配置文件:appl
- 下一篇: 【Spring注解系列01】@Confi