设计模式:观察者模式(有利于代码解耦)
什么是ApplicationContext??
它是Spring的核心,Context我們通常解釋為上下文環(huán)境,但是理解成容器會(huì)更好些。?
ApplicationContext則是應(yīng)用的容器。
Spring把Bean(object)放在容器中,需要用就通過(guò)get方法取出來(lái)。
?
ApplicationEvent
是個(gè)抽象類,里面只有一個(gè)構(gòu)造函數(shù)和一個(gè)長(zhǎng)整型的timestamp。
ApplicationListener
是一個(gè)接口,里面只有一個(gè)onApplicationEvent方法。
所以自己的類在實(shí)現(xiàn)該接口的時(shí)候,要實(shí)裝該方法。
?
如果在上下文中部署一個(gè)實(shí)現(xiàn)了ApplicationListener接口的bean,
那么每當(dāng)在一個(gè)ApplicationEvent發(fā)布到 ApplicationContext時(shí),
這個(gè)bean得到通知。其實(shí)這就是標(biāo)準(zhǔn)的Oberver設(shè)計(jì)模式。
?
一個(gè)Demo:
package com;import org.springframework.context.ApplicationEvent;/*** Created by MyWorld on 2016/7/31.*/ public class DemoEvent extends ApplicationEvent{public DemoEvent(Object source) {super(source);} }?
package com;import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component;/*** Created by MyWorld on 2016/7/31.*/ @Component public class DemoObserver1 implements ApplicationListener<DemoEvent> {@Overridepublic void onApplicationEvent(DemoEvent demoEvent) {System.out.println(this.getClass().getCanonicalName() + " receive: " + demoEvent.getSource());} }?
package com;import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component;/*** Created by MyWorld on 2016/7/31.*/ @Component public class DemoObserver2 implements ApplicationListener<DemoEvent> {@Overridepublic void onApplicationEvent(DemoEvent demoEvent) {System.out.println(this.getClass().getCanonicalName() + " receive: " + demoEvent.getSource());} }?
package com;import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.stereotype.Component;/*** Created by MyWorld on 2016/7/31.*/ @Component public class DemoSubject implements ApplicationEventPublisherAware {private ApplicationEventPublisher eventPublisher;@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.eventPublisher = applicationEventPublisher;}public void publish() {eventPublisher.publishEvent(new DemoEvent("Hello world!"));} }測(cè)試類:
package com;import com.DemoConfig; import com.DemoSubject; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/*** Created by MyWorld on 2016/7/31.*/ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {DemoConfig.class}) public class DemoSubjectTest {@Autowiredprivate DemoSubject demoSubject;@Testpublic void testPublish() throws Exception {demoSubject.publish();} }執(zhí)行結(jié)果:
"C:\Program Files\Java\jdk1.8.0_65\bin\java" -ea -Didea.launcher.port=7535 "-Didea.launcher.bin.path=D:\Program Files\JetBrains\IntelliJ IDEA 14.1.6\bin" -Dfile.encoding=GBK -classpath "D:\Program Files\JetBrains\IntelliJ IDEA 14.1.6\lib\idea_rt.jar;D:\Program Files\JetBrains\IntelliJ IDEA 14.1.6\plugins\junit\lib\junit-rt.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\rt.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\access-bridge.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\zipfs.jar;D:\source\git\EventDemo\target\test-classes;D:\source\git\EventDemo\target\classes;G:\java\repository\org\springframework\spring-context\4.1.6.RELEASE\spring-context-4.1.6.RELEASE.jar;G:\java\repository\org\springframework\spring-aop\4.1.6.RELEASE\spring-aop-4.1.6.RELEASE.jar;G:\java\repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;G:\java\repository\org\springframework\spring-beans\4.1.6.RELEASE\spring-beans-4.1.6.RELEASE.jar;G:\java\repository\org\springframework\spring-core\4.1.6.RELEASE\spring-core-4.1.6.RELEASE.jar;G:\java\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;G:\java\repository\org\springframework\spring-expression\4.1.6.RELEASE\spring-expression-4.1.6.RELEASE.jar;G:\java\repository\org\springframework\spring-test\4.1.6.RELEASE\spring-test-4.1.6.RELEASE.jar;G:\java\repository\junit\junit\4.12\junit-4.12.jar;G:\java\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar" com.intellij.rt.execution.application.AppMain com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 com.DemoSubjectTest 七月 31, 2016 1:50:40 下午 org.springframework.test.context.support.DefaultTestContextBootstrapper getDefaultTestExecutionListenerClassNames 信息: Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener] 七月 31, 2016 1:50:40 下午 org.springframework.test.context.support.DefaultTestContextBootstrapper instantiateListeners 信息: Could not instantiate TestExecutionListener [org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttribute] 七月 31, 2016 1:50:40 下午 org.springframework.test.context.support.DefaultTestContextBootstrapper instantiateListeners 信息: Could not instantiate TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttributeSource] 七月 31, 2016 1:50:40 下午 org.springframework.test.context.support.DefaultTestContextBootstrapper instantiateListeners 信息: Could not instantiate TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [javax/servlet/ServletContext] 七月 31, 2016 1:50:40 下午 org.springframework.test.context.support.DefaultTestContextBootstrapper getTestExecutionListeners 信息: Using TestExecutionListeners: [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@17246de, org.springframework.test.context.support.DirtiesContextTestExecutionListener@f67ac7] 七月 31, 2016 1:50:40 下午 org.springframework.context.support.GenericApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.GenericApplicationContext@1b6a447: startup date [Sun Jul 31 13:50:40 CST 2016]; root of context hierarchy com.DemoObserver1 receive: Hello world! com.DemoObserver2 receive: Hello world!Process finished with exit code 0代碼:https://github.com/helloworldtang/EventDemo.git
?
?
?
?
?
?
?
?
首先,什么是觀察者模式:多個(gè)觀察者去監(jiān)聽(tīng)主題,當(dāng)主題發(fā)生變化的時(shí)候,主題會(huì)通知所有的觀察者。?
盜用網(wǎng)上的一個(gè)圖:
從上圖的結(jié)構(gòu)可以看出,主題維護(hù)了一個(gè)觀察者類型的鏈表,每當(dāng)主題變化的時(shí)候,就會(huì)循環(huán)調(diào)用各個(gè)觀察者的對(duì)應(yīng)方法(這就是通知)。?
在觀察者模式中,又分為?推模型 和 拉模型。
- 推模型:主題向觀察者推送詳細(xì)信息。
- 拉模型:主題把自身作為一個(gè)參數(shù)發(fā)送給觀察者,觀察者需要什么信息,那么就 主題.getXX() 。
Java中的觀察者模式
再來(lái)看看 Java中的觀察者模式,最后再提一下 個(gè)人在 SpringBoot 中對(duì)于觀察者模式的實(shí)際使用。
Java 提供了 Observer接口(觀察者接口) 和 Observable 接口(被觀察者接口 / 主題接口)。源碼如下:
Observable 接口(被觀察者接口 / 主題接口):
public class Observable { private boolean changed = false; private Vector<Observer> obs; public Observable() { obs = new Vector<>(); } public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } public void notifyObservers() { notifyObservers(null); } public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); · clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } public synchronized void deleteObservers() { obs.removeAllElements(); } protected synchronized void setChanged() { changed = true; } protected synchronized void clearChanged() { changed = false; } public synchronized boolean hasChanged() { return changed; } public synchronized int countObservers() { return obs.size(); } }如上代碼:通過(guò) Vector 維護(hù)一個(gè) 觀察者類型的數(shù)組。通過(guò)調(diào)用 notifyObeservers(Object arg) 方法 來(lái)通過(guò)觀察者。在實(shí)現(xiàn)中,也是通過(guò)for 循環(huán) 通知。?
Ps:注意:從代碼上看,需要先設(shè)changed。
Observer接口(觀察者接口):
public interface Observer { void update(Observable o, Object arg); }這兩個(gè)參數(shù)的含義為:
* @param o the observable object. * @param arg an argument passed to the <code>notifyObservers</code>?
?
所以,此時(shí)即實(shí)現(xiàn)了 推模型,也實(shí)現(xiàn)了 拉模型。如果我們使用,那么分別實(shí)現(xiàn)這兩個(gè)接口即可。
SpringBoot事件機(jī)制對(duì)于觀察者模式的運(yùn)用
那么在個(gè)人的實(shí)際運(yùn)用中,做的是一個(gè)記賬的服務(wù),讓別人來(lái)調(diào)用。當(dāng)然,可以讓別人直接在他們的業(yè)務(wù)處理后面,例如購(gòu)買了XX東西,馬上就直接調(diào)用我的記賬服務(wù),但是這樣其實(shí)是一個(gè)緊耦合,由于是兩個(gè)不同的業(yè)務(wù),所以緊耦合感覺(jué)不太好。那么?觀察者模式就有利于解耦。
對(duì)于Spring Boot 的事件機(jī)制,同樣離不開(kāi) 這2個(gè)東西-主題,觀察者。 但是 ,spring boot 把 之前所說(shuō)的通知,包裝成了一個(gè) Event。下面分析這三者。
SpringBoot的主題
Spring boot 的主題 可以 由 ApplicationContext 來(lái)充當(dāng)。ApplicaitonContext 繼承于 ApplicationEventPublisher。ApplicaiotnEventPublisher 源碼如下:
public interface ApplicationEventPublisher { /** * Notify all listeners registered with this application of an application * event. Events may be framework events (such as RequestHandledEvent) * or application-specific events. * @param event the event to publish * @see org.springframework.web.context.support.RequestHandledEvent */ void publishEvent(ApplicationEvent event); }其實(shí)該接口就是我們 發(fā)布事件的接口。
SpringBoot 的觀察者
Spring Boot 的觀察者由 ApplicationListener 來(lái)進(jìn)行充當(dāng)。源碼如下:
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); }可以看到, onApplicaiton(E event) 方法即 上文所說(shuō)的 update 方法。
SpringBoot的Event
自定義事件 繼承ApplicationEvent抽象類
?
是Subject和Object傳遞消息的介質(zhì)。因?yàn)檫@個(gè)類型的特殊性、唯一性,可以作為標(biāo)識(shí)的依據(jù)。
就像Button按鈕的點(diǎn)擊事件、Move事件
?
上文所說(shuō)的 主題 和 觀察者 都有體現(xiàn),傳輸?shù)南?/span> Spring Boot 使用了一個(gè) ApplicationEvent 進(jìn)行了封裝,
源碼如下:
EventObject 源碼:
public class EventObject implements java.io.Serializable { private static final long serialVersionUID = 5516075349620653480L; /** * The object on which the Event initially occurred. */ protected transient Object source; public EventObject(Object source) { if (source == null) throw new IllegalArgumentException("null source"); this.source = source; } public Object getSource() { return source; } public String toString() { return getClass().getName() + "[source=" + source + "]"; } }由上面的代碼 可知,其實(shí) ApplicationEvent 就是 把需要傳輸?shù)南?封裝起來(lái)。這個(gè)消息并沒(méi)有想 Java 的實(shí)現(xiàn)那樣推拉模型都實(shí)現(xiàn)了,而是?只實(shí)現(xiàn)了 拉模型?。
最后,我們程序中只需要 注入ApplicaitonContext (Subject)發(fā)送消息publishEvent;
實(shí)現(xiàn) ApplicationListener 接口的Observer進(jìn)行相應(yīng)的處理即可。
要注冊(cè)事件監(jiān)聽(tīng)器,我們只需要把它配置成一個(gè)Bean即可,ApplicationContext容器會(huì)自動(dòng)將其注冊(cè)。
總結(jié)
觀察者模式實(shí)質(zhì)是 有兩個(gè) 東西:
- 一個(gè)是 主題
- 一個(gè)是觀察者
主題中維護(hù)了 觀察者列表的引用。當(dāng)主題有變更的時(shí)候,循環(huán)調(diào)用觀察者,通知其做相應(yīng)的處理。另外,不論是 Java,還是 Spring ,都是利用這個(gè)原理,只是有不同的類充當(dāng) 主題 和 觀察者。?
另外,觀察者模式有一個(gè)好處:解耦。
http://blog.csdn.net/allen215902/article/details/50747438
有事件,即有事件監(jiān)聽(tīng)器. 有人問(wèn)你spring監(jiān)聽(tīng)器有哪些你看了下文即也知道了。 事件傳播 ApplicationContext基于Observer模式(java.util包中有對(duì)應(yīng)實(shí)現(xiàn)),提供了針對(duì)Bean的事件傳播功能。通過(guò)Application. publishEvent方法,我們可以將事件通知系統(tǒng)內(nèi)所有的ApplicationListener。 事件傳播的一個(gè)典型應(yīng)用是,當(dāng)Bean中的操作發(fā)生異常(如數(shù)據(jù)庫(kù)連接失敗),則通過(guò)事件傳播機(jī)制通知異常監(jiān)聽(tīng)器進(jìn)行處理。在筆者的一個(gè)項(xiàng)目中,就曾經(jīng)借助事件機(jī)制,較好的實(shí)現(xiàn)了當(dāng)系統(tǒng)異常時(shí)在監(jiān)視終端上報(bào)警,同時(shí)發(fā)送報(bào)警SMS至管理員手機(jī)的功能。
ApplicationContext容器提供了容器內(nèi)部事件發(fā)布功能,是繼承自JavaSE標(biāo)準(zhǔn)自定義事件類而實(shí)現(xiàn)的。
JavaSE標(biāo)準(zhǔn)自定義事件結(jié)構(gòu)不在此詳細(xì)描述,一張圖很直觀的描述清楚:
EventObject,為JavaSE提供的事件類型基類,任何自定義的事件都繼承自該類,例如上圖中右側(cè)灰色的各個(gè)事件。Spring中提供了該接口的子類ApplicationEvent。
EventListener為JavaSE提供的事件監(jiān)聽(tīng)者接口(Observer),任何自定義的事件監(jiān)聽(tīng)者都實(shí)現(xiàn)了該接口,如上圖左側(cè)的各個(gè)事件監(jiān)聽(tīng)者。
Spring中提供了該接口的子類ApplicationListener接口。
JavaSE中未提供事件發(fā)布者這一角色類,由各個(gè)應(yīng)用程序自行實(shí)現(xiàn)事件發(fā)布者這一角色。Spring中提供了ApplicationEventPublisher接口作為事件發(fā)布者,并且ApplicationContext(Subject)實(shí)現(xiàn)了這個(gè)接口,擔(dān)當(dāng)起了事件發(fā)布者這一角色。
但ApplicationContext在具體實(shí)現(xiàn)上有所差異,Spring提供了ApplicationEventMulticaster接口,負(fù)責(zé)管理ApplicationListener和發(fā)布ApplicationEvent。ApplicationContext會(huì)把相應(yīng)的事件相關(guān)工作委派給ApplicationEventMulticaster接口實(shí)現(xiàn)類來(lái)做。
類圖如下所示:
?
事件發(fā)布時(shí)序圖如下:
?
-------------------------------------------------------------------------------------------------Spring中提供一些Aware相關(guān)的接口,BeanFactoryAware、 ApplicationContextAware、ResourceLoaderAware、ServletContextAware等等,其中最常用到的是ApplicationContextAware。
實(shí)現(xiàn)ApplicationContextAware的Bean,在Bean被初始后,將會(huì)被注入ApplicationContext的實(shí)例。
ApplicationContextAware提供了publishEvent()方法,實(shí)現(xiàn)Observer(觀察者)設(shè)計(jì)模式的事件傳播機(jī),提供了針對(duì)Bean的事件傳播功能。
通過(guò)Application.publishEvent方法,我們可以將事件通知系統(tǒng)內(nèi)所有的ApplicationListener。
Spring事件處理一般過(guò)程:
◆定義Event類(Subject和Observer傳遞消息的介質(zhì)),繼承org.springframework.context.ApplicationEvent。
◆編寫發(fā)布事件類Publisher(Subject),實(shí)現(xiàn)org.springframework.context.ApplicationContextAware接口。
◆覆蓋方法setApplicationContext(ApplicationContext applicationContext)和發(fā)布方法publish(Object obj)。
◆定義時(shí)間監(jiān)聽(tīng)類EventListener(Observer),實(shí)現(xiàn)ApplicationListener接口,實(shí)現(xiàn)方法onApplicationEvent(ApplicationEvent event)。
?
?
?
2.接受事件 2.1需要實(shí)現(xiàn)的接口org.springframework.context.ApplicationListener 2.2代碼示例 import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextStartedEvent;public class TradeContextListener implements ApplicationListener{@Overridepublic void onApplicationEvent(ApplicationEvent e) {System.out.println(e.getClass().toString());// TODO Auto-generated method stubif (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.測(cè)試代碼 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();}}?
?
Spring中ApplicationContext的事件機(jī)制--- 內(nèi)定事件) 在Spring中已經(jīng)定義了五個(gè)標(biāo)準(zhǔn)事件,分別介紹如下:1)????? ContextRefreshedEvent:當(dāng)ApplicationContext初始化或者刷新時(shí)觸發(fā)該事件。
2)????? ContextClosedEvent:當(dāng)ApplicationContext被關(guān)閉時(shí)觸發(fā)該事件。容器被關(guān)閉時(shí),其管理的所有單例Bean都被銷毀。
3)????? RequestHandleEvent:在Web應(yīng)用中,當(dāng)一個(gè)http請(qǐng)求(request)結(jié)束觸發(fā)該事件。
ContestStartedEvent:Spring2.5新增的事件,當(dāng)容器調(diào)用ConfigurableApplicationContext的Start()方法開(kāi)始/重新開(kāi)始容器時(shí)觸發(fā)該事件。
5) ContestStopedEvent:Spring2.5新增的事件,當(dāng)容器調(diào)用ConfigurableApplicationContext的Stop()方法停止容器時(shí)觸發(fā)該事件。
下面通過(guò)一個(gè)例子展示如何處理Spring內(nèi)定的事件(例程3.8)。創(chuàng)建一個(gè)Java工程,添加Spring開(kāi)發(fā)能力后,新建ioc.test包。在包中新建ApplicationEventListener類,實(shí)現(xiàn)ApplicationListener接口,在onApplicationEvent()方法中添加事件處理代碼,如下:
1?package?ioc.test;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()+"?事件已發(fā)生!");???
11???????? }elseif(eventinstanceof?ContextRefreshedEvent ){//如果是容器關(guān)閉事件
12???????????? System.out.println(event.getClass().getSimpleName()+"?事件已發(fā)生!");???
13???????? }elseif(eventinstanceof?ContextStartedEvent ){
14???????????? System.out.println(event.getClass().getSimpleName()+"?事件已發(fā)生!");
15???????? }elseif(eventinstanceof?ContextStoppedEvent){
16???????????? System.out.println(event.getClass().getSimpleName()+"?事件已發(fā)生!");
17???????? }else{
18???????????? System.out.println("有其它事件發(fā)生:"+event.getClass().getName());
19???????? }
20????????????????????
21???? }
22?
23?}
24?
?
?
在Spring配置文件中定義一個(gè)Bean,類為ApplicationEventListener,代碼如下:
1?<?xml version="1.0" encoding="UTF-8"?>2?<beans…………???
3?
4??? <bean id="ApplicationEventListener"?class="ioc.test.ApplicationEventListener"/>
5?
6?</beans>
7
?
?
添加含有主方法的TesMain類,在主方法中,調(diào)用容器的相應(yīng)方法,觸發(fā)Spring內(nèi)定事件,代碼如下:
1?package?ioc.test;2?
3?//import省略
4?publicclass?TesMain {
5?
6?publicstaticvoid?main(String[] args) {
7???????? AbstractApplicationContext ac=newClassPathXmlApplicationContext("applicationContext.xml");
8?????????
9?
10?//??? ac.refresh();//觸發(fā)ContextRefreshedEvent事件???????????
11???????? ac.start();//觸發(fā)ContextStartedEvent事件
12???????? ac.stop();?//觸發(fā)ContextStoppedEvent事件???????
13???????? ac.close();//關(guān)閉容器,觸發(fā)ContextClosedEvent事件
14?
15???? }
16?}
17
?
?
?
運(yùn)行主類,控制臺(tái)輸出如下:
?
?
?
?
從例子中可以知道,要注冊(cè)事件監(jiān)聽(tīng)器,我們只需要把它配置成一個(gè)Bean即可,ApplicationContext容器會(huì)自動(dòng)將其注冊(cè)。
?
http://blog.csdn.net/it_man/article/details/8440737
?
總結(jié)
以上是生活随笔為你收集整理的设计模式:观察者模式(有利于代码解耦)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 搭建一个jupyter站点做数据分析吧
- 下一篇: Android Studio中有没有类似