Spring 观察者模式详解以及自定义监听器扩展实现(下)

简介: Spring 观察者模式详解以及自定义监听器扩展实现(下)

SpringBoot 监听器加载过程

首先加载 META-INF/spring.factories 文件中的 key:ApplicationListener,value:全限定类名,然后获取到所有的实例存入 ApplicationContext 中,方便后续创建多播器对象时可以获取到这些监听器实例,注入:ApplicationContext 实例以后,就可以调用它来进行事件发布动作

通过观察以上内置监听器的源码,可以发现在这些监听器里都实现了 ApplicationListener 同时会使用到抽象类 ApplicationEvent,但这些内置监听器中的事件都是基于它抽象的实现,定义自己的事件类

事件驱动机制是基于观察者设计模式的实现,通过 ApplicationEvent 类、ApplicationListener 接口,可以通过 ApplicationContext 实现事件的发布

如下图整理了 SpringBoot 内置的监听器和事件:

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

前戏: 在事件准备发布时,首先会通过 getRunListeners 方法来获取我们在 META-INF/spring.factories 文件中的定义 SpringApplicationRunListener 接口实现类 EventPublishingRunListener,同时会完成该类的实例化操作,调用构造方法时,会初始化多路广播器对象:SimpleApplicationEventMulticaster,同时从上下文获取到前面加载好的 11 个监听器,进行绑定操作.

前戏工作做完以后,就到了发布事件的时候了

SimpleApplicationEventMulticaster#multicastEvent:在容器启动时会调用 listener#starting 方法(事件名:ApplicationStartingEvent)、环境对象准备前会调用 listener#environmentPrepared(事件名:ApplicationEnvironmentPreparedEvent)

以 ConfigFileApplicationListener 为例,会在其内部处理配置文件的解析工作,接受 ApplicationEnvironmentPreparedEvent 事件的处理,源码如下:

public void onApplicationEvent(ApplicationEvent event) {
      if (event instanceof ApplicationEnvironmentPreparedEvent) {
          this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);
      }
      if (event instanceof ApplicationPreparedEvent) {
          this.onApplicationPreparedEvent(event);
      }
  }

自定义监听器扩展实现

通过几个不同类型自定义事件案例来加深对事件驱动机制的理解

监听所有事件

先创建一个自定义监听器,来监听所有的事件;创建一个 Java 类,实现 ApplicationListener 接口在泛型中指定要监听的事件类型即可,如果要监听所有的事件,那么泛型就写 ApplicationEvent

public class MySpringApplicationListener implements ApplicationListener<ApplicationEvent> {
  @Override
  public void onApplicationEvent(ApplicationEvent event) {
    System.out.println("自定义监听器--->" + event);
  }
}

之后为了在容器启动中能够发现我们的监听器并且添加到 SimpleApplicationEventMulticaster 中,我们需要在 spring.factories/META-INF 中注册自定义的监听器

org.springframework.context.ApplicationListener=\
com.vnjohn.demo.listener.MySpringApplicationListener

这样当我们启动服务的时候就可以看到相关事件发布,我们的监听器被触发了,会打印对应的信息

监听特定事件

如果是监听特定的事件,我们只需要在泛型出指定类型即可

public class MySpringApplicationStartingListener implements ApplicationListener<ApplicationStartingEvent> {
  @Override
  public void onApplicationEvent(ApplicationStartingEvent event) {
    // 该事件是启动启动时就会进行发布的,查询容器启动日志信息即可 
    System.out.println("MySpringApplicationStartingListener--------->" + event);
  }
}
org.springframework.context.ApplicationListener=\
com.vnjohn.demo.listener.MySpringApplicationListener,\
com.vnjohn.demo.listener.MySpringApplicationStartingListener

启动服务时可以看到相关的事件发布

自定义事件

若我们想要通过自定义的监听器来监听自定义的事件呢?首先创建自定义的事件类,非常简单,只需要继承 ApplicationEvent 即可

public class MyEvent extends ApplicationEvent {
  public MyEvent(Object source) {
    super(source);
  }
}

然后在自定义的监听器中监听自定义的事件

public class MyCustomerEventListener implements ApplicationListener<MyEvent> {
  @Override
  public void onApplicationEvent(MyEvent event) {
    System.out.println("MyCustomerEventListener ---》自定义事件触发" + event);
    // 触发对应的事件后 业务处理
    new Thread(()->{
      // 业务....
    }).start();
  }
}

事件的监听和发布是同步执行的,如果想让其异步的进行,可以抛给一个线程进行处理

org.springframework.context.ApplicationListener=\
com.vnjohn.demo.listener.MySpringApplicationListener,\
com.vnjohn.demo.listener.MySpringApplicationStartingListener,\
com.vnjohn.demo.listener.MyCustomerEventListener

之后我们就可以在我们特定的业务场景中类发布对应的事件了

@Component
public class MyApplicationContextAware implements ApplicationContextAware {
  private static ApplicationContext applicationContext;
  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    MyApplicationContextAware.applicationContext = applicationContext;
  }
  public static void publishEvent(ApplicationEvent applicationEvent) {
    applicationContext.publishEvent(applicationEvent);
  }
}
@RestController
public class HelloController {
  @GetMapping("/hello")
  public String hello(){
    MyApplicationContextAware.publishEvent(new MyEvent(new Object()));
    return "hello---";
  }
}

当提交请求后,对应的监听器就触发了,这样一来不光搞清楚了 SpringBoot 中的监听机制,而且也可以扩展使用到我们业务开发中了

总结

希望对你有所帮助,您的支持是对我最大的鼓励,关注+赞+收藏三连,感谢!

如果觉得博文不错,关注我 vnjohn,后续会有更多实战、源码、架构干货分享!

大家的「关注❤️ + 点赞👍 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下文见!

目录
相关文章
|
5天前
|
监控 Java 应用服务中间件
Spring Boot应用的部署与扩展
Spring Boot应用的部署与扩展
|
2天前
|
JSON 监控 Java
Spring Boot中的自定义健康检查
Spring Boot中的自定义健康检查
|
7天前
|
存储 Java Apache
整合Spring Boot和Pulsar实现可扩展的消息处理
整合Spring Boot和Pulsar实现可扩展的消息处理
|
9天前
|
消息中间件 Java Maven
深入理解Spring Boot Starter:概念、特点、场景、原理及自定义starter
深入理解Spring Boot Starter:概念、特点、场景、原理及自定义starter
|
1天前
|
安全 Java Spring
Spring Boot中的自定义过滤器
Spring Boot中的自定义过滤器
|
3天前
|
Java Maven Spring
Spring Boot中的自定义Starter开发
Spring Boot中的自定义Starter开发
|
3天前
|
监控 Java 应用服务中间件
Spring Boot应用的部署与扩展
Spring Boot应用的部署与扩展
|
7天前
|
Java Maven 开发者
使用Spring Boot创建自定义Starter
使用Spring Boot创建自定义Starter
|
7天前
|
存储 Java Apache
整合Spring Boot和Pulsar实现可扩展的消息处理
整合Spring Boot和Pulsar实现可扩展的消息处理
|
7天前
|
JSON 监控 Java
Spring Boot中的自定义健康检查
Spring Boot中的自定义健康检查