Spring中的觀察者模式

1、Spring中觀察者模式的四個角色

1.事件(ApplicationEvent)java

ApplicationEvent 是全部事件對象的父類。ApplicationEvent 繼承自 jdk 的 EventObject, 全部的事件都須要繼承 ApplicationEvent, 而且經過source獲得事件源。git

下列描述了Spring提供的內置事件:github

  • 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)web

ApplicationListener 事件監聽器,也就是觀察者。繼承自 jdk 的 EventListener,該類中只有一個方法 onApplicationEvent。當監聽的事件發生後該方法會被執行。spring

3.事件發佈(ApplicationContext)app

ApplicationContext 是 Spring 中的核心容器,在事件監聽中 ApplicationContext 能夠做爲事件的發佈者,也就是事件源。由於 ApplicationContext 繼承自 ApplicationEventPublisher。在 ApplicationEventPublisher 中定義了事件發佈的方法 — publishEvent(Object event)異步

4.事件管理(ApplicationEventMulticaster)ide

ApplicationEventMulticaster 用於事件監聽器的註冊和事件的廣播。監聽器的註冊就是經過它來實現的,它的做用是把 Applicationcontext 發佈的 Event 廣播給它的監聽器列表。post

2、Spring中實現觀察者模式

  1. 自定義須要發佈的事件類,須要繼承 ApplicationEvent 類或 PayloadApplicationEvent (該類也僅僅是對 ApplicationEvent 的一層封裝)
  2. 使用 @EventListener 來監聽事件或者實現 ApplicationListener 接口。
  3. 使用 ApplicationEventPublisher 來發布自定義事件(@Autowired注入便可)

@TransactionalEventListener 監聽器:若是事件的發佈不是在事務(@Transactional)範圍內,則監聽不到該事件,除非將 fallbackExecution 標誌設置爲 true(@TransactionalEventListener(fallbackExecution = true));若是在事務中,能夠選擇在事務的哪一個階段來監聽事件,默認在事務提交後監聽(@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION))。單元測試

以上介紹的事件監聽都是同步,若是須要開啓異步支持的話:

@Configuration
@EnableAsync
public class AsyncEventConfiguration implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        return Executors.newCachedThreadPool();
    }
}

3、 實戰

事件(MyEvent.java)

@Component
public class MyEvent extends ApplicationEvent {


    public MyEvent(ApplicationContext source) {
        super(source);
        System.out.println("MyEvent 構造器執行");
    }

    public void echo() {
        System.out.println("模擬業務邏輯執行");
    }
}

事件監聽(MyListenerA.java、MyListenerB.java)

@Component
public class MyListenerA implements ApplicationListener<MyEvent> {


    @Override
    public void onApplicationEvent(MyEvent myEvent) {
        System.out.println("MyListenerA");
        myEvent.echo();
    }
}
@Component
public class MyListenerB {
    
    @EventListener
    public void onApplicationEvent(MyEvent myEvent) {
        System.out.println("MyListenerB");
        myEvent.echo();
    }
    
}

事件發佈(MyPublisher.java)

@Component
public class MyPublisher implements ApplicationContextAware {

    private ApplicationContext applicationContext;


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 發佈事件
     * 監聽該事件的監聽者均可以獲取消息
     *
     * @param myEvent
     */
    public void publisherEvent(MyEvent myEvent) {
        System.out.println("---開始發佈 myEvent 事件---");
        applicationContext.publishEvent(myEvent);
    }
}

單元測試

@RunWith(SpringRunner.class)
@SpringBootTest
public class DesignPatternsApplicationTests {

    @Autowired
    private MyPublisher myPublisher;
    @Autowired
    private MyEvent myEvent;

    @Test
    public void contextLoads() {
        myPublisher.publisherEvent(myEvent);
    }
}

演示源代碼 :https://github.com/JMCuixy/design-patterns/tree/master/src/main/java/com/example/observer/spring

相關文章
相關標籤/搜索