破·新 | 初探spring事件applicationEvent

破·新 | 初探spring事件applicationEvent

前言

不知道各位小伙伴对事件(event)这个比较抽象的名词如何理解,从我实际开发和使用经验来说,事件通常指的是某一特定条件下触发的一组操作。

做过生态开发(ISV)的小伙伴一定对事件不陌生,因为在和这些生态厂商(钉钉、企微、飞书等)进行业务交互的时候,总是避不开事件的,我们总是要对接他们的各种事件,比如入职事件、离职事件、用户变更事件、部门变更事件等等。

今天我们就来通过一个简单的示例,来演示下ApplicationListener应用级事件的使用流程。

ApplicationEvent

是什么

一个事件主要包括以下几个要素:

  • 事件注册
  • 事件监听
  • 事件触发

所以ApplicationEvent就是spring提供的一套集事件注册、监听、触发为一体的事件实现。

如何用

创建项目及模块配置

首先我们需要创建一个spring-boot项目,然后在项目的resouces/META-INF文件夹下增加名为spring.factories的文件,如果文件夹不存在,需要手动创建。

这个文件的作用是配置spring boot的常用组件,当然我们也可以通过注解的方式进行配置,关于注解的说明我们后面再说。

我们需要在文件中增加如下配置:

org.springframework.context.ApplicationListener=io.github.syske.springbootbeanlisttest.listener.SyskeApplicationListener

这个文件除了可以配置ApplicationListener之外,还可以配置EnvironmentPostProcessorPropertySourceLoaderSpringApplicationRunListener,这几个组件的应用,我们后期也会逐一分享。

这种配置方式其实就是SPI机制,这种配置的好处是,可以在不变更项目代码的基础上实现组件的增加和移除。

创建自己的ApplicationListener,这里需要实现ApplicationListener接口,并实现onApplicationEvent方法,事件触发时,会执行该方法。

public class SyskeApplicationListener implements ApplicationListener<SyskeApplicationEvent{
    @Override
    public void onApplicationEvent(SyskeApplicationEvent event) {
        String eventName = event.getEventName();
        System.out.println(eventName);
        Object eventBody = event.getEventBody();
        System.out.println(eventBody);
    }
}

这个方法的入参是ApplicationEvent或者它的子类,所以这里我们可以根据需要自定义自己的事件,并继承ApplicationEvent

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

    private String eventName;

    private Object eventBody;
    // getter/setter方法省略
}

事件注册

因为我们是直接在spring boot项目中使用的spring的事件组件,所以我们并不需要自己去做时间的注册,因为在spring boot的启动过程中,会帮我们把事件进行注册,关于这块的内容,我在之前分享spring boot启动过程的时候已经分享过了,感兴趣的小伙伴可以去看下(时间久到我都忘记了🐶):

破·新 | 初探spring事件applicationEvent

这里放一个启动流程的图:破·新 | 初探spring事件applicationEvent从上面这个图中,我们可以清楚地看到,这里获取了所有的SpringApplicationRunListener,并分别执行了他们的startingstarted方法,但是这里的listener并不是我们的事件监听器,而是spring boot的运行监听器,但是我们事件监听器的初始化确实是在这里完成的,因为这里也初始化了我们事件的运行监听器,并执行了它的的startingstarted方法:破·新 | 初探spring事件applicationEvent破·新 | 初探spring事件applicationEvent好了,至此,我们知道spring boot的事件是何时注册的,下面我们来一起看下事件如何触发。

事件触发

事件的触发,没啥好解释的,就是让事件监听器的onApplicationEvent方法执行

 SyskeApplicationEvent syskeApplicationEvent = new SyskeApplicationEvent("test");
        syskeApplicationEvent.setEventName("sysk-event");
        syskeApplicationEvent.setEventBody("sysk-body");
        applicationContext.publishEvent(syskeApplicationEvent);
测试
@GetMapping("/event")
    public Object testEvent() {
        SyskeApplicationEvent syskeApplicationEvent = new SyskeApplicationEvent("test");
        syskeApplicationEvent.setEventName("sysk-event");
        syskeApplicationEvent.setEventBody("sysk-body");
        applicationContext.publishEvent(syskeApplicationEvent);
        return "success";
    }

运行结果:破·新 | 初探spring事件applicationEvent

其实,除了我们上面展示的这种配置方式,spring boot还提供了另一套更简单便捷的事件实现方式:

@Component
public class Syske2ApplicationListenerConfig {

    @EventListener
    public void onApplicationEvent(Syske2ApplicationEvent event) {
        String eventName = event.getEventName();
        System.out.println(eventName);
        Object eventBody = event.getEventBody();
        System.out.println(eventBody);
        System.out.println("Syske2ApplicationEvent");
    }
}

也就说,我们只需要定义自己的事件,然后编写事件触发的操作方法,并在方法上加上@EventListener即可,这里的方法名无关紧要,可以随便指定,事件的触发也没有任何区别:

破·新 | 初探spring事件applicationEvent另外,根据实际测试发现,spring boot的事件是支持多监听的,也就是类似于广播消息,这里我两个地方都监听了同一个事件,可以看到两个地方都被触发了:破·新 | 初探spring事件applicationEvent

知识扩展

事件

除了今天我们介绍的ApplicationEvent之外,还有很多优秀的开源事件组件,比如guavaeventBus,后面有机会的话,我们可以单独分享下eventBus的用法。

spring.factories

在今天的内容中,我们在resouces/META-INF文件夹下,创建了spring.factories文件,其实在spring-boot的核心jar文件的META-INF文件夹也是有这个文件的,当然文件的内容更完整,它包括了以下配置:

  • 资源加载器(org.springframework.boot.env.PropertySourceLoader
  • 运行监听器(org.springframework.boot.SpringApplicationRunListener
  • 错误报告器(org.springframework.boot.SpringBootExceptionReporter
  • 应用上下文初始化组件(org.springframework.context.ApplicationContextInitializer
  • 应用监听器(org.springframework.context.ApplicationListener
  • 环境后置处理器(org.springframework.boot.env.EnvironmentPostProcessor
  • 失败分析组件(org.springframework.boot.diagnostics.FailureAnalyzer
  • 失败分析报告组件(org.springframework.boot.diagnostics.FailureAnalysisReporter

当然,并不是所有的公司都会用到事件,因为事件本身有一些局限性,比如说如果你的服务是集群环境的话,事件是不可以多节点共享的,所以很多公司可能会更愿意用mq

其实,关于事件的使用场景以及为什么要使用事件,我觉得我好像还没想明白,在我看来,事件应该是类似于异步线程池一样的存在,当然这样的思考可能有失偏薄,毕竟每一种技术的存在都是为了解决某些其他技术解决不了的问题~

好了,今天的内容就到这里吧,感谢各位小伙伴的支持,晚安哟

– END –


原文始发于微信公众号(云中志):破·新 | 初探spring事件applicationEvent

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/40227.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!