事件的监听与发布

有些时候,我们希望某件事情发生的时候能够触发一个事件,让这个事件帮我们做些事情。比如,在晚上十一点到晚上十二点这段时间,假如还有人在使用我们的软件,我们就触发一个事件播放一首美妙的音乐,希望用户听了之后能够做个好梦,美美睡上一觉。而这,我们需要做好三件事情:
1.定义一个事件。
2.定义一个事件监听器:如果事件监听器监听到事件发布了,就会触发事件监听器,播放一首美妙的音乐。
3.定义一个类:能够判断当前时间是否在晚上十一点与晚上十二点之间;如果是,就发布事件。

这样一来,我们期望的功能就能实现了。因此,我们首先需要做的,就是定义一个事件:

这是一个音乐事件,继承了ApplicationEvent类。ApplicationEvent是Spring提供的一个事件抽象类,凡是事件都应继承它。而我们的音乐事件继承ApplicationEvent抽象类后,做了这些事情:
1.定义一个构造函数。构造函数只是简单地调用父类的构造函数,把Object类型的参数传给父类。Object类型的参数是事件发布的事件源。
2.定义一个String类型的musicName属性,用于存放这个事件应该播放的音乐名。

于是,音乐事件定义好了。下一步,我们需要定义一个事件监听器:

这是一个音乐事件监听器,实现了ApplicationListener接口。ApplicationListener是Spring提供的一个泛型接口,凡是事件监听器都应实现它;其签名如下:

这是一个函数式泛型接口。实现这个接口的时候,需要指定一个继承了ApplicationEvent类的子类。这样,当指定类型的事件发布的时候,事件监听器就能监听到指定类型的事件,调用onApplicationEvent方法进行处理。因此,音乐事件监听器实现ApplicationListener
1.调用musicEvent事件的getMusicName方法获取音乐名。
2.向控制台输出一段文字,告诉用户正在为您播放某首音乐。

这样一来,一旦音乐事件监听器监听到音乐事件发布了,就会触发音乐事件监听器,调用onApplicationEvent方法播放音乐。因此,下一步我们需要做的,就是发布事件:

这段代码定义了一个类,该类实现了ApplicationEventPublisherAware接口。这是一个Aware接口,能让Spring容器注入ApplicationEventPublisher类型的Bean

ApplicationEventPublisher是个接口。在ApplicationContext实现的众多接口中,其中就有ApplicationEventPublisher接口。因此,ApplicationContext也是ApplicationEventPublisher类型的。Spring容器注入的ApplicationEventPublisher类型的Bean其实就是ApplicationContext本身。

问题在于,ApplicationEventPublisher是干嘛的?为什么需要注入一个ApplicationEventPublisher类型的Bean?

简单来说,ApplicationEventPublisher就是一个事件发布器,专门用于发布事件的。其定义了一个void publishEvent(ApplicationEvent event)方法,能够发布ApplicationEvent类型的事件。

因此,MusicService的play方法做了这件事情:获取当前时间的小时,判断当前时间的小时是否等于23,以此判断当前时间是不是在晚上十一点到晚上十二点之间。如果是,则进行事件的发布;否则什么也不做。事件发布的流程是这样的:
1.创建一个MusicEvent类型的事件。
2.以MusicEvent类型的事件为参数,调用ApplicationEventPublisher的publishEvent方法发布事件。

因此,我们只要调用MusicService的play方法就能发布事件了。从而触发音乐事件监听器,让音乐事件监听器播放音乐。为此,我们需要写个Java配置类,告诉Spring容器创建相应的Bean:

之后,我们只需要在main函数里使用Java配置类创建一个Spring容器,从Spring容器里拿到ID为musicService的Bean之后调用Bean的play方法就能发布事件了:

我们调用ID为musicService的Bean的play方法发布了一个音乐事件,使音乐事件监听器监听到音乐事件之后播放那首名为《Dream》的音乐。

需要注意的是,事件的发布与监听是同步的。也就是说,play方法发布事件之后需要等到监听器完成事件的处理之后才能接着往下执行。还有,现在的事件是通过继承ApplicationEvent抽象类实现的,事件监听器则是通过实现ApplicationListener接口实现的。我们也能使用@EventListener注解做同样的事情,只要对MusicEvent和MusicListner稍做改动就行。

具体而言,MusicEvent已经不需要继承ApplicationEvent抽象类了。可以把它改成一个普通的类:

同样的,MusicListener也不需要实现ApplicationListener接口。可以把它改成一个普通的类,再把@EventListener注解加到MusicListener的方法上即可:

MusicListener再也没有实现ApplicationListener接口,而是定义了onMusicEvent方法,再在方法上面添加@EventListener注解,就能监听MusicEvent事件。另外,如果希望监听器异步处理发布的事件,可往监听器方法添加@Async注解,如下所示:

于是,关于如何添加自定义事件的介绍就告一段落了。需要了解的是,Spring还内置了些事件:
1.ContextRefreshedEvent:Spring容器完成初始化或刷新之后就会发布这个事件。
2.ContextStartedEvent:Spring容器调用start()方法启动之后就会发布这个事件。
3.ContextStoppedEvent:Spring容器调用stop()方法停止之后就会发布这个事件。
4.ContextClosedEvent:Spring容器调用close()方法关闭之后就会发布这个事件。
5.RequestHandledEvent:Web请求完成处理之后就会发布这个事件。
6.ServletRequestHandledEvent:和RequestHandledEvent一样,也是Web请求完成处理之后就会发布这个事件。只是这个事件多了一些Servlet的上下文信息。

使用这些内置事件的时候,只要实现这些事件的监听器即可。这里不再介绍。

至此,关于事件的监听与发布的介绍也就告一段落了。下章,我们将会开始介绍面向切面编程。欢迎大家继续阅读,谢谢大家!

Original: https://www.cnblogs.com/evanlin/p/16127200.html
Author: 林雪波
Title: 事件的监听与发布

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/571380/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Java 17中对switch的模式匹配增强

    通过下面这个例子再回忆一下: Map data = new HashMap<>(); data.put("key1", "aaa&quot…

    Java 2023年6月9日
    080
  • VS Code插件

    怎么安装插件? 方法一: 按F1或Ctrl+Shift+p,输入extensions,点击第一个安装扩展就可以 方法二: ctrl + P 然后输入 ext install 方法三…

    Java 2023年6月7日
    0116
  • 解决.net mvc session超时的问题

    在.NET MVC中session的默认有效期是20分钟 调整的方式是在项目的Web.config中进行配置,如下方式可以调整为120分钟。 <system.web> …

    Java 2023年5月29日
    066
  • Java使用FreeMarker模版技术动态生成word实践

    一、序言 在日常开发中,常常有动态word文件生成的需求,通过编制模版,然后动态修改word内容以组合成新的文件。报告单、请假单、发票页等都可以使用动态生成word来解决。 笔者总…

    Java 2023年6月6日
    083
  • MyBatis的基本介绍及优势

    MyBatis 的历史由来 Mybatis 原本是 Apache 软件基金会的一个开源项目叫做 iBatis ,2010 年这个项目由 Apache 迁移到了 google cod…

    Java 2023年6月5日
    098
  • Springboot优雅参数校验,统一响应,异常处理

    1.统一响应 (1)统一状态码首先定义一个状态码接口,所有状态码都需要实现它 public interface StatusCode { public int getCode();…

    Java 2023年6月8日
    075
  • 对于Java中权限修饰符的理解

    老是把Java中权限修饰符给忘记,写一个博客加深印象吧 权限分为四个作用域:当前类,同一个包,其他包的子类,其他包的类。 首先要知道包的概念,Java中一个包是指一个package…

    Java 2023年6月15日
    069
  • MyBatis入门配置

    ​ 目录 一、创建数据库 二、创建mybatis核心配置文件 三、配置pom.xml 四、创建pojo 五、创建工具类获取SqlSession对象 六、创建Dao层接口 七、创建D…

    Java 2023年6月7日
    055
  • 朱晔和你聊Spring系列S1E9:聊聊Spring的那些注解

    本文我们来梳理一下Spring的那些注解,如下图所示,大概从几方面列出了Spring的一些注解:如果此图看不清楚也没事,请运行下面的代码输出所有的结果。Spring目前的趋势是使用…

    Java 2023年5月30日
    092
  • JavaWeb作用域

    JavaWeb作用域 综述 javaweb有四个不同级别的作用域,分别是page页面级别、一次请求级别、一次会话级别、整个web级别。page没有进行实现 请求级别 只对一次req…

    Java 2023年6月8日
    086
  • 三流大学和一流大学学生的简历有什么区别?

    最近公司秋招,我写了一篇秋招文章,吸引了不少跃跃欲试的小伙伴,看着邮箱里形形色色的简历,不禁感慨,果然大家对敖丙是真爱,知道我最近比较缺素材,疯狂给我输送反面教材。 简历有忘记写名…

    Java 2023年6月9日
    077
  • 不到 20 人的 IT 公司该去吗?

    来源:https://www.zhihu.com/question/421150601 群里经常有一些朋友问:一些初创的IT公司,一共几个人的配置,老板+1-2个前端+3-4个后端…

    Java 2023年6月15日
    0110
  • 为什么阿里Java开发手册不推荐使用Timestamp?

    开发手册 网上解释不推荐用 java.sql.Date、 java.sql.Time的文章有很多,但是解释为什么不推荐使用 java.sql.Timestamp文章没找到。 参考文…

    Java 2023年6月6日
    090
  • 太空射击python

    import random import pygame from os import path img_dir = path.join(path.dirname(__file__)…

    Java 2023年6月14日
    088
  • 关于数据拓展及面试题讲解 Java

    强类型语言 要求变量的使用严格符合规定,所有变量都必须先定义后才能使用 弱类型语言 Java 的数控类型分为两大类 基本类型(primitive type ) 引用类型(refer…

    Java 2023年6月5日
    075
  • Spring 常见面试题总结 | JavaGuide

    首发于 JavaGuide 在线网站:Spring 常见面试题总结 最近在对 JavaGuide 的内容进行重构完善,同步一下最新更新,希望能够帮助你。 Spring 基础 什么是…

    Java 2023年6月9日
    075
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球