javascript
Spring的事件发布机制
一:Spring的事件發(fā)布
??? ApplicationContext提供了針對Bean的事件傳播功能,其中的主角是publishEvent()方法,通過這個方法可以將事件通知給系統(tǒng)內(nèi)的監(jiān)聽器(需實現(xiàn)ApplicationListener接口)。
??? ApplicationContext這個接口,是Spring的上下文,通常獲取Bean就需要這個接口,這個接口并不是直接繼承于BeanFactory,其中最著名的是直接繼承了ApplicationPublisher接口,這個接口查看源碼可以發(fā)現(xiàn):只有一個方法,那就是主角 void publishEvent(ApplicationEvent event);
??? Spring提供的基于Aware相關(guān)的接口有ApplicationContextAware,ResourceloaderAware,ServletContextAware(注意:Struts2也有這個接口,注意區(qū)分),最常用的就這三個,而Spring的事件發(fā)布機制需要用到ApplicationContextAware接口。
??? 實現(xiàn)了ApplicationContextAware的Bean,在Bean初始化時將會被注入ApplicationContext實例(因為這個接口里有set(ApplictationContext ctx)方法)
二:有了以上基礎(chǔ),看示例代碼:
1.首先創(chuàng)建事件類 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.然后編寫 事件的發(fā)布者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; /** ?* 事件的發(fā)布者 ?* @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()方法里發(fā)布了事件 |
| 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("監(jiān)聽到的事件:"+event.getSource()); ????} } |
| 1 | 事件的接收者其實是一個監(jiān)聽器,必須實現(xiàn)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.結(jié)果顯示:
結(jié)果中已經(jīng)顯示監(jiān)聽到的事件,說明成功。
Spring 中的事件監(jiān)聽的實現(xiàn)
這里我們不討論事件監(jiān)聽的機制的原理,我們只討論如何在項目中實現(xiàn)時間監(jiān)聽。?
Spring的事件監(jiān)聽是基于觀察者模式。設(shè)計開發(fā)中。如下類與接口是我們必須要使用的。
ApplicationContext
首先我們了解一下ApplicationContext,還記得
ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");- 1
ApplicationContext相當于Spring的一個與IOC容器連接的橋梁,通過getBean();方法,我們可以輕松的從IOC容器中獲取Bean對象。?
因為ApplicationContext是實現(xiàn)ApplicationEventPublisher的。查看ApplicationEventPublisher的源碼,我們發(fā)現(xiàn)有一方法publishEvent。此方法便是發(fā)布事件的方法,即觸發(fā)事件的方法,通過調(diào)用publishEvent方法,注入事件ApplicationEvent的子類,實現(xiàn)事件的觸發(fā)。
- 1
- 2
- 1
- 2
- 3
- 4
- 5
- 6
說了一大堆,就是想說ApplicationContext的
publicEvent(ApplicationEvent event);
方法是可以用來發(fā)布通知,相當于觸發(fā)事件的事件源。
ApplicationContextAware
ApplicationContextAware類似于ServeletRequestAware,通過讓Action實現(xiàn)Aware,使得Action初始化之后便可以獲得一些資源,這里我們讓Action實現(xiàn)ApplicationContext,使得Action擁有ApplicationContext,Action中擁有ApplicationContext之后就可以調(diào)用publicEvent方法進行通知
public interface ApplicationContextAware extends Aware {void setApplicationContext(ApplicationContext applicationContext) throws BeansException;}- 1
- 2
- 3
- 4
ApplicationEvent
ApplicationEvent相當于一個事件,所有自定義事件都需要繼承這個抽象類。在Eclipse中Ctrl+Shift+H調(diào)用類的層次結(jié)構(gòu)列表,可以看到如下?
?
Application下抽象子類ApplicationContextEvent的下面有4個已經(jīng)實現(xiàn)好的事件?
ContextClosedEvent(容器關(guān)閉時)?
ContextRefreshedEvent(容器刷新是)?
ContextStartedEvent(容器啟動時候)?
ContextStoppedEvent(容器停止的時候)?
同樣,這四個事件都繼承了ApplicationEvent,如果我們想自定義事件,也可以通過繼承ApplicationEvent來實現(xiàn)?
嗯,同樣是一句話總結(jié)ApplicationEvent就是一個抽象類,創(chuàng)建時間的時候只需要繼承它就可以。
ApplicationListener
從名字可以看出來,這是一個監(jiān)聽器。為什么需要監(jiān)聽器呢?監(jiān)聽器是用于接收事件,并觸發(fā)事件的操作,這樣說起來可能有點費解,簡單的說就是,Listener是監(jiān)聽ApplicationContext.publishEvent,方法的調(diào)用,一旦調(diào)用publishEvent,就會執(zhí)行ApplicaitonListener中的方法,下面這個是ApplicationContext的源碼。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {/*** publishEvent觸發(fā)該方方法* 可以在該方法中寫各種業(yè)務(wù)邏輯*/void onApplicationEvent(E event);}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
這里是實際代碼實現(xiàn)的過程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
2.新建一個監(jiān)聽器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> {//調(diào)用ApplicationContext.publishEvent方法時會觸發(fā)執(zhí)行該方法@Overridepublic void onApplicationEvent(ApplicationEvent event) {//判斷事件為MyEvent時候執(zhí)行if(event instanceof MyEvent){//強制轉(zhuǎn)換MyEvent evt=(MyEvent) event;//執(zhí)行自定義事件中的自定義方法evt.myevent();}//如果容器關(guān)閉時,觸發(fā)if(event instanceof ContextClosedEvent){ContextClosedEvent cce=(ContextClosedEvent) event;System.out.println("#####################");System.out.println("容器關(guān)閉");System.out.println(cce);System.out.println("#####################");}//容器刷新時候觸發(fā)if(event instanceof ContextRefreshedEvent){ContextRefreshedEvent cre=(ContextRefreshedEvent) event;System.out.println("#####################");System.out.println("容器刷新");System.out.println(cre);System.out.println("#####################");}//容器啟動的時候觸發(fā)if(event instanceof ContextStartedEvent){ContextStartedEvent cse=(ContextStartedEvent) event;System.out.println("#####################");System.out.println("容器啟動");System.out.println(cse);System.out.println("#####################");}//容器停止時候觸發(fā)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中發(fā)布通知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原型,對應每一個請求都會產(chǎn)生一個實例對象 @Controller("elecTextAction") @Scope(value="prototype") public class ElecTextAction extends BaseAction<ElecText> implements ApplicationContextAware,ServletRequestAware {//首先獲得模型驅(qū)動對象ElecText elecText=getModel();protected ApplicationContext applicationContext;//注入Service指定從Spring的IOC容器中注入的對象的名稱@Resource(name=IElecTextService.SERVICE_NAME)private IElecTextService elecTextService;public String save(){//從表單中傳送過來的實例對象elecTextService.saveElecText(elecText);/*** 請關(guān)注這一行代碼,在頁面中訪問時候調(diào)用save方法* save方法中執(zhí)行了publishEvent方法發(fā)布通知。* 傳入?yún)?shù)是自定義事件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
訪問頁面的時候,命令行輸出,可以看出,觸發(fā)了MyEvent方法輸出。
********My event************** 在Action中的save方法Public了Event *******************************總結(jié)
以上是生活随笔為你收集整理的Spring的事件发布机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring boot配置文件:appl
- 下一篇: java.lang.ClassCastE