theme: channing-cyan
前言
- 上篇博客spring 5.0.x源碼學習系列九: FactoryBean和BeanFactory主要介紹了spring中的兩個特殊的bean, FactoryBean和BeanFactory。本次团南,咱們將開始介紹下spring的事件驅動模型以及它使用的設計模式: 觀察者設計模式废睦。
一、觀察者模式
1.1 根據(jù)一個案例實現(xiàn)一個觀察者設計模式
- 假設有這么一個場景驶臊,小黃和小楊一起在看電影籽暇,當電影播放到精彩的劇情時局齿,小黃小楊分別會有不同的行為表現(xiàn)。小黃會睡覺悠菜,小楊會哭泣舰攒。下面我們將使用代碼來模擬出這個案例。
1.1.1 版本1
-
Application.java入口類
-
Huang.java小黃實體類
-
Yang.java小楊實體類
-
Movie.java電影類
-
運行結果
- 小結:
- 使用上述的方式實現(xiàn)了案例的需求悔醋,但有如下缺點
- 觀察者需要全程觀看電影摩窃,占用觀察者大量時間
- 當電影播放到精彩部分的時候自己來主動通知自己要做些事情了。
1.1.2 版本二
-
修復了版本一的問題:
- 由電影來通知觀察者芬骄,省去觀察者需要全程觀看電影的缺點猾愿,由電影來通知觀察者該做一些事情了
-
Application.java
-
Huang.java
-
Yang.java
-
Movie.java
-
運行結果
-
小結,版本二的觀察者模式具有如下缺點:
- 觀察者的行為動作不統(tǒng)一账阻,被觀察者代碼維護難度大
- 擴展性低蒂秘,若觀察者需要增加,則需要手動在被觀察中添加觀察者的引用淘太,重復工作多
1.1.3 版本3
- 此版本修復了版本2的缺點:
- 觀察者行為動作不統(tǒng)一
- 擴展性低
-
MovieObserver.java
-
Application.java
-
Huang.java
-
Movie.java
-
Yang.java
-
運行結果
- 小結
- 版本3是觀察者模式的基本模型姻僧,但是它并沒有抽象出事件的概念规丽。其實也抽象出來了。MovieObserver相當于事件的監(jiān)聽者撇贺,Movie播放精彩部分的動作是一個事件赌莺。notifyObservers相當于發(fā)布事件。
1.1.4 版本4
此版本基于版本3做了些修改, 將事件松嘶、監(jiān)聽者艘狭、發(fā)布事件的概念添加了進去
-
MovieEvent.java
-
MovieListener.java
-
Application.java
-
Huang.java
-
Movie.java
-
Yang.java
-
運行結果
-
小結
- 版本4將事件的概念抽象了出來,會根據(jù)發(fā)布不同的事件響應不同的行為
- 在此版本中翠订,一共定義了兩種類型的事件感人類型事件, 喜劇類型事件
1.2 觀察者設計模式特點
- 被觀察者持有觀察者的引用
- 耦合性低巢音,被觀察者在
特定時間
發(fā)布特定事件
,觀察者具體的行為動作由觀察者自己決定 - 提供新增和移除觀察者api蕴轨,可任意擴容觀察者數(shù)量
二港谊、Spring 事件模型
2.1 spring事件模型類型
- ApplicationContextEvent
- RequestHandlerEvent
2.2 ApplicationContextEvent事件觸發(fā)步驟
-
新建自定義事件源骇吭。繼承ApplicationEvent類, 并重寫帶參構造方法
public class MyApplicationEvent extends ApplicationEvent { // 帶參構造方法中的參數(shù)就是可以為事件添加一些參數(shù), 即 // 自定義一些事件 public MyApplicationEvent(Object source) { super(source); } }
-
新建事件監(jiān)聽器橙弱。
// 1. 需要添加@Component注解, 讓監(jiān)聽者作為spring的一個bean // 2. 其次, 要實現(xiàn)ApplicationListener接口, 泛型為上述定義的事件源(MyApplicationEvent) @Component public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> { @Override public void onApplicationEvent(MyApplicationEvent event) { System.out.println("監(jiān)聽者, " + event); } }
-
獲取spring ApplicationEventPublisher對象
// 新建了一個bean來維護上下文對象 @Component public class ApplicationContextHolder implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { applicationContext = applicationContext; } public static ApplicationContext getApplicationContext() { return applicationContext; } }
-
觸發(fā)事件
// 拿到spring上下文發(fā)布事件 // spring上下文如何拿到? spring上下文是指實現(xiàn)了ApplicationContext接口的類 // 在以java config技術開啟的spring應用程序中, 可以用AnnotationConfigApplicationContext的實例, 第三步可以忽略 // 若是spring web應用程序, eg: spring mvc, 則可以新增一個bean并實現(xiàn)ApplicationContextAware接口, eg: 第三步 ApplicationContextHolder.getApplicationContext().publishEvent(new MyApplicationEvent(new String[] { "1", "2" }))
2.3 ApplicationContextEvent的四種類型總結
類型 | 如何觸發(fā) | 觸發(fā)時機 | spring 上下文初始化后是否能觸發(fā) |
---|---|---|---|
ContextRefreshEvent | 發(fā)布類型為ContextRefreshEvent的事件. | 調用spring上下文refersh方法 | 是 |
ContextStopEvent | 發(fā)布類型為ContextStopEvent的事件 | 調用spring上下文stop方法 | 否 |
ContextStartEvent | 發(fā)布類型為ContextStartEvent的事件 | 調用spring上下文start方法 | 否 |
ContextCloseEvent | 發(fā)布類型為ContextCloseEvent的事件 | 調用spring上下文close方法 | 否 |
- 上述的觸發(fā)時機可參考此url:https://github.com/AvengerEug/observer-csdn/blob/develop/src/main/java/springevent/Entry.java
2.4 RequestHandlerEvent類型的事件
- 待總結
三燥狰、總結
- Spring事件驅動模型是基于觀察者設計模式衍生而來的棘脐,jdk也有自帶的觀察者設計模式類,分別是被觀察者: Observable龙致,觀察者: Observer蛀缝。但jdk自帶的觀察者設計模式類并沒有把事件集成進去,雖然JDK中存在事件相關的類目代,比如EventObject類屈梁,但僅僅是被應用到了java swing編程。
- 本次博客代碼倉庫地址: https://github.com/AvengerEug/observer-csdn.git
- I am a slow walker, but I never walk backwards.