SpringBoot 如何使用@EventListener实现事件监听机制

导语
  我们先回顾下设计模式中的观察者模式,因为事件监听机制可以说是在典型观察者模式基础上的进一步抽象和改进。我们可以在JDK或者各种开源框架比如Spring中看到它的身影,从这个意义上说,事件监听机制也可以看做一种对传统观察者模式的具体实现,不同的框架对其实现方式会有些许差别。下面就来详细看一下事件发布监听机制

文章目录

  • 什么是事件监听机制
  • JDK中对事件监听机制的支持
  • Spring容器对事件监听机制的支持
    • 如何实现基于注解的事件处理机制
      • 事件发布器
      • 事件源
      • 事件监听器
  • 总结

什么是事件监听机制

  典型的观察者模式将有依赖关系的对象抽象为了观察者和主题两个不同的角色,多个观察者同时观察一个主题,两者只通过抽象接口保持松耦合状态,这样双方可以相对独立的进行扩展和变化:比如可以很方便的增删观察者,修改观察者中的更新逻辑而不用修改主题中的代码。但是这种解耦进行的并不彻底,这具体体现在以下几个方面:

  • 1.抽象主题需要依赖抽象观察者,而这种依赖关系完全可以去除。
  • 2.主题需要维护观察者列表,并对外提供动态增删观察者的接口,
  • 3.主题状态改变时需要由自己去通知观察者进行更新。

  我们可以把主题(Subject)替换成事件(event),把对特定主题进行观察的观察者(Observer)替换成对特定事件进行监听的监听器(EventListener),而把原有主题中负责维护主题与观察者映射关系以及在自身状态改变时通知观察者的职责从中抽出,放入一个新的角色事件发布器(EventPublisher)中,事件监听模式的轮廓就展现在了我们眼前,如下图所示
SpringBoot 如何使用@EventListener实现事件监听机制_第1张图片

常见事件监听机制的主要角色如下

  • 事件及事件源:对应于观察者模式中的主题。事件源发生某事件是特定事件监听器被触发的原因。
  • 事件监听器:对应于观察者模式中的观察者。监听器监听特定事件,并在内部定义了事件发生后的响应逻辑。
  • 事件发布器:事件监听器的容器,对外提供发布事件和增删事件监听器的接口,维护事件和事件监听器之间的映射关系,并在事件发生时负责通知相关监听器。

JDK中对事件监听机制的支持

  在JDK java.util.EventObject的类,所有的实现自定义的事件类型都需要继承并且实现这个类。

public class EventObject implements java.io.Serializable {
     

    private static final long serialVersionUID = 5516075349620653480L;

    /**
     * The object on which the Event initially occurred.
     */
    protected transient Object  source;

    /**
     * Constructs a prototypical Event.
     *
     * @param    source    The object on which the Event initially occurred.
     * @exception  IllegalArgumentException  if source is null.
     */
    public EventObject(Object source) {
     
        if (source == null)
            throw new IllegalArgumentException("null source");

        this.source = source;
    }

    /**
     * The object on which the Event initially occurred.
     *
     * @return   The object on which the Event initially occurred.
     */
    public Object getSource() {
     
        return source;
    }

    /**
     * Returns a String representation of this EventObject.
     *
     * @return  A a String representation of this EventObject.
     */
    public String toString() {
     
        return getClass().getName() + "[source=" + source + "]";
    }
}

  分析源码可以看到在这个类中有一个Object source的变量,逻辑上是作为事件发生的事件源,在实际的使用中可以包含一些事件的源信息。既然了事件源,就必须要有事件的监听机制。在JDK中java.util.EventListener表示对于JDK封装的事件的监听

/**
 * A tagging interface that all event listener interfaces must extend.
 * @since JDK1.1
 */
public interface EventListener {
     
}

  以上就是JDK为我们实现自定义事件监听提供的底层支持。针对具体业务场景,我们通过扩展java.util.EventObject来自定义事件类型,同时通过扩展java.util.EventListener来定义在特定事件发生时被触发的事件监听器。当然,不要忘了还要定义一个事件发布器来管理事件监听器并提供发布事件的功能。也就是需要一个Publisher来发布事件消息。

  下面就来分析一下Spring是如何实现事件处理的

Spring容器对事件监听机制的支持

  Spring容器,具体而言是ApplicationContext接口定义的容器提供了一套相对完善的事件发布和监听框架,其遵循了JDK中的事件监听标准,并使用容器来管理相关组件,使得用户不用关心事件发布和监听的具体细节,降低了开发难度也简化了开发流程。下面看看对于事件监听机制中的各主要角色,Spring框架中是如何定义的,以及相关的类体系结构
SpringBoot 如何使用@EventListener实现事件监听机制_第2张图片

如何实现基于注解的事件处理机制

事件发布器

public class ResApplyCheckingPublisher {
     
	
	@Autowired
	private ApplicationContext applicationContext;

	/**
	 * 用来推送邮件消息
	 */
	@Async
	public void publish(){
     
		ResApplyCheckingEvent event = new ResApplyCheckingEvent();
		applicationContext.publishEvent(event);
	}
}

事件源

public class ResApplyCheckingEvent extends ResApplyEvent {
     	
	public ResApplyCheckingEvent() {
     
		super();
	}
}

定制化的事件封装

public abstract class ResApplyEvent extends ApplicationEvent {
     

	//定制化的开发最后Object source 传入当前对象或者是封装好的对象
	public ResApplyEvent(Object source) {
     
		super(source);
	}
}

ApplicationEvent

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;
	}

}

事件监听器

  事件监听实现机制有两种一种是实现ApplicationListener接口,第二种就是使用注解的方式,这里使用注解的方式

//发送给部门负责人
@EventListener
public void toSendDeptLeaderEmail(ResApplyCheckingEvent applyCheckEvent) {
     
    // 1. 获取到事件信息
    // 2. 校验场景信息
    return;
}

实现下面接口定制化的开发,然后将实现类注入到容器中,就可以完成对于时间的监听。

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
     

	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);

}

注意以上所有的内容都要在容器中进行注册

总结

  通过观察者模式的引入,实现了Java底层对于事件监听机制的封装,而Spring则是对于JDK的事件机制做了进一步的封装。后续还会为大家分享如何将事件处理机制封装成一个邮件场景启动器。

你可能感兴趣的:(SpringBoot基础,Spring,事件监听)