Spring中的事件驱动模型(一)

事件驱动模型

事件驱动模型通常也被理解成观察者或者发布/订阅模型。

  • 是一种对象间的一对多的关系;
  • 当目标发送改变(发布),观察者(订阅者)就可以接收到改变;
  • 观察者如何处理,目标无需干涉,它们之间的关系是松耦合的。

event-source

事件驱动模型的例子很多,如生活中的红绿灯,以及我们在微服务中用到的配置中心,当有配置提交时出发具体的应用实例更新Spring上下文环境。

Spring的事件机制

基本概念

Spring的事件驱动模型由三部分组成:

  • 事件:ApplicationEvent,继承自JDK的EventObject,所有事件将继承它,并通过source得到事件源。
  • 事件发布者:ApplicationEventPublisher及ApplicationEventMulticaster接口,使用这个接口,我们的Service就拥有了发布事件的能力。
  • 事件订阅者:ApplicationListener,继承自JDK的EventListener,所有监听器将继承它。

Spring事件驱动过程

事件

Spring 默认对 ApplicationEvent 事件提供了如下实现:

  • ContextStoppedEvent:ApplicationContext停止后触发的事件;
  • ContextRefreshedEvent:ApplicationContext初始化或刷新完成后触发的事件;
  • ContextClosedEvent:ApplicationContext关闭后触发的事件。如web容器关闭时自动会触发Spring容器的关闭,如果是普通java应用,需要调用ctx.registerShutdownHook()注册虚拟机关闭时的钩子才行;
  • ContextStartedEvent:ApplicationContext启动后触发的事件;

eventobject

 1public abstract class ApplicationEvent extends EventObject {
 2    private static final long serialVersionUID = 7099057708183571937L;
 3    //事件发生的时间
 4    private final long timestamp = System.currentTimeMillis();
 5    //创建一个新的ApplicationEvent事件
 6    public ApplicationEvent(Object source) {
 7        super(source);
 8    }
 9
10    public final long getTimestamp() {
11        return this.timestamp;
12    }
13}

事件基类ApplicationEvent,所有的具体事件都会继承该抽象事件类。

事件监听者

ApplicationListener

ApplicationListener继承自JDK的EventListener,JDK要求所有监听器将继承它。

1@FunctionalInterface
2public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
3    void onApplicationEvent(E var1);
4}

提供了onApplicationEvent方法,用以处理ApplicationEvent,不过对于具体事件的处理需要进行判断。而GenericApplicationListenerSmartApplicationListener提供了关于事件更多的元数据信息。

 1public class SourceFilteringListener implements GenericApplicationListener, SmartApplicationListener {
 2
 3    private final Object source;
 4
 5    @Nullable
 6    private GenericApplicationListener delegate;
 7
 8    //为特定事件源创建SourceFilteringListener,并传入代理的监听器类
 9    public SourceFilteringListener(Object source, ApplicationListener<?> delegate) {
10        this.source = source;
11        this.delegate = (delegate instanceof GenericApplicationListener ?
12                (GenericApplicationListener) delegate : new GenericApplicationListenerAdapter(delegate));
13    }
14    //....省略部分代码
15
16    @Override
17    public int getOrder() {
18        return (this.delegate != null ? this.delegate.getOrder() : Ordered.LOWEST_PRECEDENCE);
19    }
20
21    //过滤之后实际处理事件
22    protected void onApplicationEventInternal(ApplicationEvent event) {
23        //...
24        this.delegate.onApplicationEvent(event);
25    }
26
27}

SourceFilteringListenerApplicationListener的装饰器类,过滤特定的事件源。只会注入其事件对应的代理监听器,还提供了按照顺序触发监听器等功能。 在启动的时候会加载一部分 ApplicationListener。Spring Context加载初始化完成(refresh)后会再次检测应用中的 ApplicationListener,并且注册,此时会将我们实现的 ApplicationListener 就会加入到 SimpleApplicationEventMulticaster 维护的 Listener 集合中。 Spring也支持直接注解的形式进行事件监听@EventListener(Event.class)

事件发布

EventPublisher

ApplicationContext接口继承了ApplicationEventPublisher,并在AbstractApplicationContext实现了具体代码,实际执行是委托给ApplicationEventMulticaster

1@FunctionalInterface
2public interface ApplicationEventPublisher {
3    //通知所有的注册该事件的应用,事件可以是框架事件如RequestHandledEvent或者特定的应用事件。
4    default void publishEvent(ApplicationEvent event) {
5        this.publishEvent((Object)event);
6    }
7
8    void publishEvent(Object var1);
9}

实际的执行是委托给,读者有兴趣可以看一下AbstractApplicationContext中这部分的逻辑。下面我们具体看一下ApplicationEventMulticaster接口中定义的方法。

 1public interface ApplicationEventMulticaster {
 2
 3    //增加监听者
 4    void addApplicationListener(ApplicationListener<?> listener);
 5    //...
 6
 7    //移除监听者
 8    void removeApplicationListener(ApplicationListener<?> listener);
 9    //...
10
11    //广播特定事件给监听者
12    void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
13
14}

AbstractApplicationContext中定义了对监听者的操作维护,如增加和删除,并提供了将特定事件进行广播的方法。下面看一下具体实现类SimpleApplicationEventMulticasterApplicationContext自动到本地容器里找一个ApplicationEventMulticaster实现,如果没有则会使用默认的SimpleApplicationEventMulticaster

 1public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
 2
 3    @Nullable
 4    private Executor taskExecutor;
 5
 6    //...
 7
 8    //用给定的beanFactory创建SimpleApplicationEventMulticaster
 9    public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
10        setBeanFactory(beanFactory);
11    }
12
13    @Override
14    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
15        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
16        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
17            Executor executor = getTaskExecutor();
18            if (executor != null) {
19                executor.execute(() -> invokeListener(listener, event));
20            }
21            else {
22                invokeListener(listener, event);
23            }
24        }
25    }
26
27    //注入给定事件的给定监听器
28    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
29        ErrorHandler errorHandler = getErrorHandler();
30        if (errorHandler != null) {
31            try {
32                doInvokeListener(listener, event);
33            }
34            ...
35        }
36        else {
37            doInvokeListener(listener, event);
38        }
39    }
40
41    @SuppressWarnings({"unchecked", "rawtypes"})
42    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
43        try {
44            listener.onApplicationEvent(event);
45        }
46        //...
47    }
48
49}

multicastEvent方法中,executor不为空的情况下,可以看到是支持异步发布事件。发布事件时只需要调用ApplicationContext中的publishEvent方法即可进行事件的发布。

总结

本文主要介绍了Spring中的事件驱动模型相关概念。首先介绍事件驱动模型,也可以说是观察者模式,在我们的日常生活中和应用开发中有很多应用。随后重点篇幅介绍了Spring的事件机制,Spring的事件驱动模型由事件、发布者和订阅者三部分组成,结合Spring的源码分析了这三部分的定义与实现。笔者将会在下一篇文章,结合具体例子以及Spring Cloud Config中的实现进行实战讲解。

参考

  1. 事件驱动模型简介
  2. Spring事件驱动模型与观察者模式

原文发布于微信公众号 - aoho求索(aohoBlog)

原文发表时间:2018-02-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏猿天地

Spring Boot Async异步执行任务

异步调用就是不用等待结果的返回就执行后面的逻辑,同步调用则需要等带结果再执行后面的逻辑。

1712
来自专栏服务端技术杂谈

Motan源码阅读--调用示例

异步调用和同步调用基本配置一样,只需要在接口类中加@MotanAsync注解,然后Client端稍作修改,server端不需要做任何修改。

1363
来自专栏代码拾遗

Spring Boot 2.0 教程 - 配置详解

Spring Boot 可以通过properties文件,YAML文件,环境变量和命令行参数进行配置。属性值可以通过,@Value注解,Environment...

1213
来自专栏java思维导图

mybatis-plus思维导图,让mybatis-plus不再难懂

 Mybatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果...

1.4K18
来自专栏Java学习123

Java中的日志——Java.util.logging、log4j、commons-logging

2999
来自专栏XAI

SpringMVC+MongoDB+Maven整合(微信回调Oauth授权)

个人小程序。里面是基于百度大脑 腾讯优图做的人脸检测。是关于人工智能的哦。 2017年第一篇自己在工作中的总结文档。土豪可以打赏哦。 https://git.o...

8887
来自专栏chenssy

【追光者系列】HikariCP源码分析之故障检测那些思考 fail fast &amp; allowPoolSuspension

由于时间原因,本文主要内容参考了 https://segmentfault.com/a/1190000013136251,并结合一些思考做了增注。

1832
来自专栏扎心了老铁

zookeeper curator使用caches实现各种监听

1、篇首语 curator是zookeeper的一个高级api开发包。封装了zookeeper众多的recipes,并且实现了一些新的recipes原语,最重要...

5595
来自专栏黑泽君的专栏

day32_Hibernate学习笔记_04

  缓存(Cache):是计算机领域非常通用的概念。它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写硬盘(永久性数...

1022
来自专栏王磊的博客

简单的小工具wordlight——让VS变量高亮起来

前段时间一直在使用matlab,今天需要使用vs2008,而用惯了matlab,习惯了其中一项选中变量高亮的设置,突然回来使用VS,感到各种不适应,顿时想到了一...

3766

扫码关注云+社区

领取腾讯云代金券