Spring Event 的幕后

简介: Spring Event 基于观察者模式,实现模块间松散耦合的通信。通过事件(Event)、事件发布者(Publisher)和事件监听器(Listener)三个核心组件,Spring Event 可以轻松实现业务解耦。Spring 容器在启动时会初始化 `ApplicationEventMulticaster`,扫描并注册所有事件监听器,通过调用 `multicastEvent()` 方法将事件广播给所有注册的监听器。

 Spring Event 基于发布-订阅模式(观察者模式),使得系统中不同模块可以通过事件进行松散耦合的通信,而不需要直接依赖彼此,使用Spring Event,可以轻松实现业务解耦。

观察者模式

  观察者模式(Observer Pattern)是一种行为设计模式,它定义了一种一对多的依赖关系,使得一个对象(被观察者,Subject)可以通知多个观察者(Observers)对象,在其状态发生变化时,所有依赖它的对象都会收到通知并自动更新。

  观察者模式中有四个角色(一般情况):目标、具体目标、观察者、具体观察者。在JDK中使用Observer接口和Observable类来作为观察者模式的抽象层,再自定义具体观察者类和具体观察目标类,可以方便地应用观察者模式。

Spring Event

为什么前面要简单的回顾了观察者模式呢?

  事实上,Spring Event 是观察者模式的一种具体实现。Spring Event 机制的设计围绕三个核心组件展开:事件(Event)、事件发布者(Publisher)和事件监听器(Listener)。

具体实现

  • 事件(Event)

java

代码解读

复制代码

@Getter
public class TypeComputationEvent extends ApplicationEvent {

    String orderNo;
    String status;

    public TypeComputationEvent(Object source,String orderNo,String status) {
        super(source);
        this.orderNo = orderNo;
        this.status = status;
    }
}

  事件是系统中某个动作或状态改变的标识,在 Spring 中,事件通常是一个继承自 ApplicationEvent 的类。

  • 事件发布者(Publisher)

java

代码解读

复制代码

applicationEventPublisher.publishEvent(new TypeComputationEvent(this"orderNo","status"))

  事件发布者是触发事件的组件,在 Spring 中,任何组件都可以充当事件发布者,只需要通过依赖注入的方式获取 ApplicationEventPublisher 的实例,然后调用其 publishEvent() 方法发布事件。

  • 事件监听器(Listener)

java

代码解读

复制代码

@Slf4j
@Component
@RequiredArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
public class TypeComputationListener {

    @EventListener
    public void onApplicationEvent(TypeComputationEvent event) {
        log.info("=====>>>订单状态变更事件,订单号:{}", event.getOrderNo());

    }

}

  事件监听器用于当事件发布后,所有监听该事件的监听器都会被触发并执行相应的处理逻辑。Spring 提供了 @EventListener 注解,只需将其标注在方法上,该方法就会在相应事件发生时自动执行。@TransactionalEventListener注解 通过与 Spring 的事务管理器集成,使得事件处理与事务的生命周期紧密相关。具体来说,它允许你指定在事务提交前或后处理事件。

  默认情况下,ApplicationListener处理事件是同步执行的,在某些情况下,事件处理逻辑可能会比较耗时,为了避免阻塞主线程,可以通过 @Async 注解将事件处理逻辑异步化。

java

代码解读

复制代码

@Slf4j
@Component
@RequiredArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
public class TypeComputationListener {

    @EventListener
    @Async
    public void onApplicationEvent(TypeComputationEvent event) {
        log.info("=====>>>订单状态变更事件,订单号:{}", event.getOrderNo());

    }

}

实现原理

  Spring 的事件处理机制涉及到 ApplicationEventMulticaster 组件,这个组件是事件发布和监听的核心部分。

  • ApplicationEventMulticaster 初始化,在 Spring 容器初始化过程中被创建

java

代码解读

复制代码

protected void initApplicationEventMulticaster() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   // 如果手动新建了一个ApplicationEventMulticaster类型为的bean,则将这个bean作为事件广播器
   if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
      this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
      if (logger.isTraceEnabled()) {
         logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
      }
   }
   else {
      // 否则,新建一个SimpleApplicationEventMulticaster作为默认的事件广播器
      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
      if (logger.isTraceEnabled()) {
         logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
               "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
      }
   }
}
  • registerListeners 注册监听器,在 Spring 容器初始化过程中被创建

java

代码解读

复制代码

protected void registerListeners() {
   // 把监听器添加到监听器容器中
   for (ApplicationListener<?> listener : getApplicationListeners()) {
      getApplicationEventMulticaster().addApplicationListener(listener);
   }

   // 获取类型是ApplicationListener的beanName集合
   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
   for (String listenerBeanName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
   }

   
   Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
   this.earlyApplicationEvents = null;
   if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
         getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
   }
}

  Spring 容器在启动时会扫描所有的 @EventListener 注解或实现了 ApplicationListener 接口的类,并将这些监听器注册到 ApplicationEventMulticaster 中。

  • multicastEvent发布事件

  当我们通过applicationEventPublisher.publishEvent()发布事件时,会调用 ApplicationEventMulticaster.multicastEvent() 方法,会将事件传递给所有匹配的监听器。

java

代码解读

复制代码

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
   Executor executor = getTaskExecutor();
   for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
         invokeListener(listener, event);
      }
   }
}

总结

  Spring Event 通过 Spring 容器初始化时创建并配置 ApplicationEventMulticaster 实例,扫描并注册所有事件监听器(通过注解或接口实现)。最后通过调用 multicastEvent() 方法,将事件广播给所有注册的监听器。Spring Event 它基于观察者模式实现,通过事件驱动的方式实现了模块间的松散耦合。


转载来源:https://juejin.cn/post/7402435366647119881

相关文章
|
监控 Java C#
Spring Event 的介绍
Spring Event 是 Spring 框架中的事件驱动机制,允许组件间进行同步或异步消息传递,无需直接依赖。它包括事件(Event)、事件发布者(Publisher)和事件监听器(Listener),通过 `ApplicationEventPublisher` 广播事件,实现松耦合通信,增强模块化和可维护性。Spring 还提供了多种内置事件,如 `ContextRefreshedEvent` 和 `ContextClosedEvent`,支持同步及异步处理,并具备良好的扩展性。
503 3
|
消息中间件 Java Kafka
【Azure Kafka】使用Spring Cloud Stream Binder Kafka 发送并接收 Event Hub 消息及解决并发报错
reactor.core.publisher.Sinks$EmissionException: Spec. Rule 1.3 - onSubscribe, onNext, onError and onComplete signaled to a Subscriber MUST be signaled serially.
284 6
|
消息中间件 Java 开发工具
【Azure 事件中心】Spring Cloud Stream Event Hubs Binder 发送Event Hub消息遇见 Spec. Rule 1.3 - onSubscribe, onNext, onError and onComplete signaled to a Subscriber MUST be signaled serially 异常
【Azure 事件中心】Spring Cloud Stream Event Hubs Binder 发送Event Hub消息遇见 Spec. Rule 1.3 - onSubscribe, onNext, onError and onComplete signaled to a Subscriber MUST be signaled serially 异常
308 0
|
Java Spring
【Azure 事件中心】Spring Boot 集成 Event Hub(azure-spring-cloud-stream-binder-eventhubs)指定Partition Key有异常消息
【Azure 事件中心】Spring Boot 集成 Event Hub(azure-spring-cloud-stream-binder-eventhubs)指定Partition Key有异常消息
267 0
|
Java Spring
Spring Event陷阱重重,我为何含泪放弃?
网络上比较推崇使用Spring Event 优雅的实现观察者模式。我在调研后也确实觉得这种方式能实现业务逻辑上的解耦,但线上的一次事故,让我意识到 Spring Event远远没有那么简单。
1066 1
Spring Event陷阱重重,我为何含泪放弃?
|
Java Spring
深入理解Spring IOC之扩展篇(十)、SpringBoot中重要event介绍,顺便简单讲下SB的启动流程(二)
深入理解Spring IOC之扩展篇(十)、SpringBoot中重要event介绍,顺便简单讲下SB的启动流程(二)
288 0
|
XML Java 数据格式
深入理解Spring IOC之扩展篇(九)、SpringBoot中重要event介绍,顺便简单讲下SB的启动流程(一)
深入理解Spring IOC之扩展篇(九)、SpringBoot中重要event介绍,顺便简单讲下SB的启动流程(一)
331 0
|
设计模式 缓存 Java
深入理解Spring IOC之扩展篇(七)、Spring中的event以及自定义event
深入理解Spring IOC之扩展篇(七)、Spring中的event以及自定义event
432 0
|
设计模式 Java Spring
Spring Boot Event 观察者模式,轻松带你实现业务解耦!
Spring Boot Event 观察者模式,轻松带你实现业务解耦!
424 0
Spring Boot Event 观察者模式,轻松带你实现业务解耦!
|
消息中间件 存储 架构师
【首席架构师看Event Hub】Kafka深挖 -第2部分:Kafka和Spring Cloud Stream
【首席架构师看Event Hub】Kafka深挖 -第2部分:Kafka和Spring Cloud Stream