Spring中的觀察者模式
一、Spring中觀察者模式的四個角色
1.事件(ApplicationEvent)
ApplicationEvent 是所有事件物件的父類。ApplicationEvent 繼承自 jdk 的 EventObject, 所有的事件都需要繼承 ApplicationEvent, 並且通過source得到事件源。
下列描述了Spring提供的內建事件:
- ContextRefreshedEvent:事件釋出在 ApplicationContext 初始化或重新整理時(例如:通過在 ConfigurableApplicationContext 介面使用refresh()方法)。這裡,“初始化”意味著所有 bean 載入,post-processor bean 被檢測到並且啟用,單例預先例項化,ApplicationContext 物件可以使用了。只要上下文沒有關閉,可以觸發多次重新整理, ApplicationContext 提供了一種可選擇的支援這種“熱”重新整理。例如:XmlWebApplicationContext 支援熱重新整理,但 GenericApplicationContext 並非如此。具體是在 AbstractApplicationContext 的 finishRefresh() 方法中。
- ContextStartedEvent:事件釋出在 ApplicationContext 開始使用 ConfigurableApplicationContext 介面 start() 方法。這裡,“開始”意味著所有生命週期 bean 接收到一個明確的起始訊號。通常,這個訊號用於明確停止後重新啟動,但它也可以用於啟動元件沒有被配置為自動執行(例如:元件還沒有開始初始化)。
- ContextStoppedEvent:事件釋出在 ApplicationContext 停止時通過使用 ConfigurableApplicationContext 介面上的 stop() 方法。在這裡,“停止”意味著所有生命週期bean接收一個顯式的停止訊號。停止上下文可以通過重新呼叫start()方法。
- ContextClosedEvent:事件釋出在 ApplicationContext 關閉時通過關閉 ConfigurableApplicationContext 介面()方法。這裡,“封閉”意味著所有單例 bean 被摧毀。一個封閉的環境達到生命的終結。它不能重新整理或重啟。
- RequestHandledEvent:一個特定的web事件告訴所有能處理HTTP請求的bean 。這個事件是在請求完成後釋出的。這個事件只適用於使用 Spring 的 DispatcherServlet 的web應用程式。
2.事件監聽(ApplicationListener)
ApplicationListener 事件監聽器,也就是觀察者。繼承自 jdk 的 EventListener,該類中只有一個方法 onApplicationEvent。當監聽的事件發生後該方法會被執行。
3.事件釋出(ApplicationContext)
ApplicationContext 是 Spring 中的核心容器,在事件監聽中 ApplicationContext 可以作為事件的釋出者,也就是事件源。因為 ApplicationContext 繼承自 ApplicationEventPublisher。在 ApplicationEventPublisher 中定義了事件釋出的方法 — publishEvent(Object event)
4.事件管理(ApplicationEventMulticaster)
ApplicationEventMulticaster 用於事件監聽器的註冊和事件的廣播。監聽器的註冊就是通過它來實現的,它的作用是把 Applicationcontext 釋出的 Event 廣播給它的監聽器列表。
二、Spring中實現觀察者模式
- 自定義需要釋出的事件類,需要繼承 ApplicationEvent 類或 PayloadApplicationEvent (該類也僅僅是對 ApplicationEvent 的一層封裝)
- 使用 @EventListener 來監聽事件或者實現 ApplicationListener 介面。
- 使用 ApplicationEventPublisher 來發布自定義事件(@Autowired注入即可)
@TransactionalEventListener 監聽器:如果事件的釋出不是在事務(@Transactional)範圍內,則監聽不到該事件,除非將 fallbackExecution 標誌設定為 true(@TransactionalEventListener(fallbackExecution = true));如果在事務中,可以選擇在事務的哪個階段來監聽事件,預設在事務提交後監聽(@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION))。
以上介紹的事件監聽都是同步,如果需要開啟非同步支援的話:
1 @Configuration 2 @EnableAsync 3 public class AsyncEventConfiguration implements AsyncConfigurer { 4 @Override 5 public Executor getAsyncExecutor() { 6 return Executors.newCachedThreadPool(); 7 } 8 }
三、 實戰
事件(MyEvent.java)
1 @Component 2 public class MyEvent extends ApplicationEvent { 3 4 5 public MyEvent(ApplicationContext source) { 6 super(source); 7 System.out.println("MyEvent 構造器執行"); 8 } 9 10 public void echo() { 11 System.out.println("模擬業務邏輯執行"); 12 } 13 }
事件監聽(MyListenerA.java、MyListenerB.java)
1 @Component 2 public class MyListenerA implements ApplicationListener<MyEvent> { 3 4 5 @Override 6 public void onApplicationEvent(MyEvent myEvent) { 7 System.out.println("MyListenerA"); 8 myEvent.echo(); 9 } 10 }
1 @Component 2 public class MyListenerB { 3 4 @EventListener 5 public void onApplicationEvent(MyEvent myEvent) { 6 System.out.println("MyListenerB"); 7 myEvent.echo(); 8 } 9 10 }
事件釋出(MyPublisher.java)
1 @Component 2 public class MyPublisher implements ApplicationContextAware { 3 4 private ApplicationContext applicationContext; 5 6 7 @Override 8 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 9 this.applicationContext = applicationContext; 10 } 11 12 /** 13 * 釋出事件 14 * 監聽該事件的監聽者都可以獲取訊息 15 * 16 * @param myEvent 17 */ 18 public void publisherEvent(MyEvent myEvent) { 19 System.out.println("---開始釋出 myEvent 事件---"); 20 applicationContext.publishEvent(myEvent); 21 } 22 }
單元測試
1 @RunWith(SpringRunner.class) 2 @SpringBootTest 3 public class DesignPatternsApplicationTests { 4 5 @Autowired 6 private MyPublisher myPublisher; 7 @Autowired 8 private MyEvent myEvent; 9 10 @Test 11 public void contextLoads() { 12 myPublisher.publisherEvent(myEvent); 13 } 14 }
演示原始碼 :https://github.com/JMCuixy/design-patterns/tree/master/src/main/java/com/example/observer/spring
轉載於:https://www.cnblogs.com/jmcui/p/11054756.html