Spring事件发布机制

目录

 前言

一、事件驱动机制

二、Spring的事件发布机制

三、Spring事件使用实例

四、Spring事件驱动的实现原理

总结:

前言

在设计模式中有一种设计模式叫做观察者设计模式,观察者模式的大致思想是这样的:有两个比较中重要的概念
一个是:被观察的对象(Subject) 一个是观察的对象(Observer)。
当被观察的对象有变更和改动的时候,能够及时的通知给Observer。
大家细品,是不是有点消息队列的味道。是的,没错。消息队列MQ的思想和观察者模式的思想是一样的。Subject的改动可以通过到每一个Observer。

有同学就会问,观察者模式也好,消息队列也好,和我们要提到Spring的事件发布机制有什么关系勒。我的理解是,在分布式的微服务中,子服务与子服务之间的通信可以选择成熟的MQ中间件来做到业务的解耦。但是如果我们要在单个子服务,不同的模块中要做到类似的功能,我们要怎么实现勒。没错就是我们要提到的Spring的事件发布机制。

—————————————————————————————————————————

一、事件驱动机制

 在事件驱动中有三个比较重要的组件:

  • Event 发布的事件对象
  • EventPublisher:事件发布对象
  • EventListener:事件监听对象

 整个流程如下图

 EventPublisher发布一个事件。携带Event对象。

所有监听这个Event的监听器到这个事件,并获取到这个Event对象,进行业务处理。

 二、Spring的事件发布机制

在Spring框架中,预留了三个接口:分别对应上面事件发布机制的三种抽象对象

分别是

  • 事件接口:ApplicationEvent  
  • 事件发布者接口:ApplicationEventPublisher
  • 事件监听接口:ApplicationEventListenr

 三、Spring事件使用实例

 我们可以去查看ApplicationContext的源代码,ApplicationContext是已经实现了ApplicationEventPublisher接口,所有任意一个ApplicationContext的实现类都可以去发布事件。

我们通过一段代码来简单介绍Spring事件驱动的使用


public class EmailEvent extends ApplicationEvent{
   …
}
 
public class SpringTest {
   public static void main(String args[]){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
     //创建一个ApplicationEvent对象
     EmailEvent event = new EmailEvent(…);
     //主动触发该事件
     context.publishEvent(event);
   }
}
 
public class EmailNotifier implements ApplicationListener<EmailEvent>{
   public void onApplicationEvent(ApplicationEvent event) {
     //监听EmailEvent事件
     if (event instanceof EmailEvent) {
        //处理EmailEvent事件
      EmailEvent emailEvent = (EmailEvent)event;
        …
     } else {
        …
     }
   }
}

 当事件发布后,在Spring的框架中就会通知所有该事件的监听器,并执行监听器的onApplication方法,并传入发布的Event对象。这样解除了事件发布和事件监听之间的耦合。

当前在Spring框架的设计中也使用一些事件驱动的事件。

比如:ContextStartedEvent、ContextStoppedEvent、ContextClosedEvent 等事件,会在 Spring 容器的生命周期处于启动、停止以及关闭阶段自动触发。如果我们对这些事件感兴趣,就可以直接实现 ApplicationListener 接口,从而对具体某一个事件进行响应。

除了上面通过显示的通过实现ApplicationListener我们也可以通过注解的方式来使用事件监听


@Component
public class TestApplicationListener
       @EventListener(classes={ EmailEvent.class})
       public void listen(EmailEvent emailEvent){
              System.out.println(contextStoppedEvent);
       }
}

四、Spring事件驱动的实现原理

了解到现在,我们可以猜测下Spring是如何实现事件发布与监听。

我们不妨想想这样的问题:

1、ApplicationEventPubliser是如何获取到对应的监听器。因为在事件发布后,需要获取到对应的事件监听器对象ApplicationListener并执行对应onApplication对象

2、初始化时机,listener对象是在时候初始化的。

首先我们先开始思考第二个问题,说到初始化,我们比较容易联想到Spring容器的启动。

没错,在Spring容器启动的时候就会去注册所有的监听器。


public void refresh() throws BeansException, IllegalStateException {
       try {
              ...
              // 初始化自定义事件广播器
              initApplicationEventMulticaster();
              // 执行刷新
              onRefresh();
              // 注册监听器
              registerListeners();
              ...
       }
}

注册的监听器,是存放在ApplicationEventMulticaster事件多播器里面。

在事件发布时候。publier对象通过获取到ApplicationEventMulticaster对象的getApplicationListener()获取监听器,然后执行对应的multicastEvent方法执行监听器的onApplicationEvent方法


public void multicastEvent(final ApplicationEvent event) {
       for (final ApplicationListener listener : getApplicationListeners(event)) {
              //获取线程执行器
              Executor executor = getTaskExecutor();
              if (executor != null) {
                     //执行监听线程
                     executor.execute(new Runnable() {
                            public void run() {     
                                listener.onApplicationEvent(event);
                            }
                     });
              }
              else {
                     listener.onApplicationEvent(event);
              }
       }
}

总结:

  1. 事件发布机制的主要使用场景:在单服务中,通过事件驱动的机制,做到事件发布对象与事件监听对象之间的解耦。
  2. Spring事件驱动的主要实现原理如下图

   

参考文章:

10分钟带你彻底搞懂Spring事件发布和监听机制-极客时间

设计模式(五)观察者模式_刘望舒的博客-CSDN博客_观察者模式


版权声明:本文为weixin_44399827原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。