基于Spring的发布订阅模式 EventListener

基于Spring的发布订阅模式在我们使用spring开发应用时,经常会碰到要去解耦合一些依赖调用 , 比如我们在做代码的发布流程中,需要去通知相关的测试,开发人员关注发布中的错误信息 。而且通知这个操作又不希望强耦合在主业务流程中,这个时候我们很容易就想到了观察者设计模式,而spring恰好提供了事件-监听机制,让我们看一下他们是具体怎么实现的吧 。
事件-监听机制:

  1. 首先是一种对象间的一对多的关系;最简单的如交通信号灯,信号灯是目标(一方),行人注视着信号灯(多方);
  2. 当目标发送改变(发布),观察者(订阅者)就可以接收到改变;
  3. 观察者如何处理(如行人如何走,是快走/慢走/不走,目标不会管的),目标无需干涉;所以就松散耦合了它们之间的关系 。
Spring提供的事件驱动模型/观察者抽象
基于Spring的发布订阅模式 EventListener

文章插图
其实整个模型就有三个角色,事件,目标(发布者),监听者,我们看一下spring中如何实现这三者
事件:具体代表者是:ApplicationEvent:
1、 我们可以看到spring中ApplicationEvent该抽象类继承自JDK的EventObject 。JDK要求所有事件将继承它,并通过source得到事件源 。
package org.springframework.context;import java.util.EventObject;/** * Class to be extended by all application events. Abstract as it * doesn't make sense for generic events to be published directly. * * @author Rod Johnson * @author Juergen Hoeller */public abstract class ApplicationEvent extends EventObject { /** use serialVersionUID from Spring 1.2 for interoperability */ private static final long serialVersionUID = 7099057708183571937L; /** System time when the event happened */ private final long timestamp; /*** Create a new ApplicationEvent.* @param source the object on which the event initially occurred (never {@code null})*/ public ApplicationEvent(Object source) {super(source);this.timestamp = System.currentTimeMillis(); } /*** Return the system time in milliseconds when the event happened.*/ public final long getTimestamp() {return this.timestamp; }}
目标(发布者)具体代表者是具体代表者是:ApplicationEventPublisher及ApplicationEventMulticaster 。ApplicationContext该接口继承了ApplicationEventPublisher,并在AbstractApplicationContext实现了具体代码 , 实际执行是委托给ApplicationEventMulticaster(可以认为是多播):
ApplicationContext继承自ApplicationEventPublisher
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,MessageSource, ApplicationEventPublisher, ResourcePatternResolver {}ApplicationEventPublisher定义了publishEvent方法
public interface ApplicationEventPublisher {/*** Notify all <strong>matching</strong> listeners registered with this* application of an application event. Events may be framework events* (such as RequestHandledEvent) or application-specific events.* @param event the event to publish* @see org.springframework.web.context.support.RequestHandledEvent*/void publishEvent(ApplicationEvent event);/*** Notify all <strong>matching</strong> listeners registered with this* application of an event.* <p>If the specified {@code event} is not an {@link ApplicationEvent},* it is wrapped in a {@link PayloadApplicationEvent}.* @param event the event to publish* @since 4.2* @see PayloadApplicationEvent*/void publishEvent(Object event);}在AbstractApplicationContext实现了具体代码,实际执行是委托给ApplicationEventMulticaster(可以认为是多播)
protected void publishEvent(Object event, ResolvableType eventType) {Assert.notNull(event, "Event must not be null");if (logger.isTraceEnabled()) {logger.trace("Publishing event in " + getDisplayName() + ": " + event);}// Decorate event as an ApplicationEvent if necessaryApplicationEvent applicationEvent;if (event instanceof ApplicationEvent) {applicationEvent = (ApplicationEvent) event;}else {applicationEvent = new PayloadApplicationEvent<Object>(this, event);if (eventType == null) {eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();}}// Multicast right now if possible - or lazily once the multicaster is initializedif (this.earlyApplicationEvents != null) {this.earlyApplicationEvents.add(applicationEvent);}else {getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);}// Publish event via parent context as well...if (this.parent != null) {if (this.parent instanceof AbstractApplicationContext) {((AbstractApplicationContext) this.parent).publishEvent(event, eventType);}else {this.parent.publishEvent(event);}}}ApplicationContext自动到本地容器里找一个ApplicationEventMulticaster实现,如果没有自己new一个SimpleApplicationEventMulticaster 。

推荐阅读