《知识点扫盲 · 监听器 Listener》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,如需交流,欢迎留言评论。👍

文章目录

    • 写在前面的话
    • **监听器简介**
    • Servlet 监听器
    • Spring 监听器
      • 实现 ApplicationListener 接口
      • 使用 @EventListener 注解
      • Spring 常见内置事件
      • 自定义事件与监听器
      • Spring 监听器原理分析
      • 实战 · 初始化监听器拓展
    • 其他监听器
    • 总结陈词


写在前面的话

上几篇博文介绍了拦截器 Interceptor和过滤器 Filter,这边接着介绍一下监听器、切面等内容,先把这一系列补充完毕,之前列的类目太广,精力有限,导致很多其他系列没接着更新,被粉丝催促。还是经验不足导致,后续改善。
话分两头,本篇文章让我们进入监听器 Listener的世界。


监听器简介

监听器是一种常见的设计模式,广泛应用于各种编程场景中。不同的框架和库都有自己的监听器机制,适用于不同类型的事件处理需求(这点和前面介绍的拦截器很像)。通过监听器,开发者可以实现事件驱动的编程模型,解耦事件的产生和处理逻辑,从而提高代码的可维护性和扩展性。
简单来说, 监听器用于监听一些重要事件的发生,以便在事情发生前、发生后可以做一些必要的处理。
场景举例:项目启动时,需要做一些预处理和初始化操作,如缓存预加载等,服务关闭时,清理线程资源等;


Servlet 监听器

Java Servlet 规范中定义了几种类型的监听器,用于监听 Web 应用程序生命周期中的各种事件。
下面展开介绍常见的几种。

1、ServletContextListener 和 ServletContextAttributeListener
ServletContextListener 可以监听到 ServletContext 的创建和销毁,而 ServletContextAttributeListener 可以监听到ServletContext 中属性的新增、移除和属性值的替换。

2、HttpSessionListener 和 HttpSessionAttributeListener
HttpSessionListener 可以监听 HttpSession 的创建跟销毁,而 HttpSessionAttributeListener 则是对 HttpSession 中属性的监听,它可以监听到 HttpSession 新增属性、移除属性和属性值被替换时;

3、ServletRequestListener 和 ServletRequestAttributeListener
ServletRequestListener 可见监听 Request 的创建和销毁;而 ServletRequestAttributeListener 可以对 Request 的属性进行监听;

上面三种从命名上也很好理解,逻辑也差不多,示例代码如下:

@Slf4j
@Component
public class ServletInitListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent servletContextEvent) {if (log.isInfoEnabled()) {log.info("Servlet启动初始化监听~");}}@Overridepublic void contextDestroyed(ServletContextEvent servletContextEvent) {if (log.isInfoEnabled()) {log.info("Servlet启动初始化监听~");}}
}

如果是SpringBoot项目,那如何让其生效?有两种方式:
1、实现监听器类后,直接加上 @Component 注解,推荐这种方式,这种方式下,你可以使用 Spring 的依赖注入功能,因为监听器类是一个 Spring Bean;
2、实现监听器类后,加上 @WebListener 注解,使用该标签时,需要在启动类上使用 @ServletComponentScan 注解,这种方式就单纯当作监听器处理,不要用依赖诸如方式操作 Bean,一定要使用就借助 SpringUtil 等方式,并且要考虑容器加载顺序问题;

总之,很简单的用法,总结就是 Servlet 监听器可以监听 ServletContext、HttpSession、ServletRequest 对象的生命周期事件以及属性改变事件。其作用是监听一些重要事件的发生,监听器对象可以在事情发生前、发生后可以做一些必要的处理。


Spring 监听器

参考:链接 链接
前面介绍完了 Servlet 监听器,比较简单,而真正在 Spring 项目的开发中,用 Spring 监听器的场景更多。
先了解一下最常见的示例:

实现 ApplicationListener 接口

下面示例监听 ContextRefreshedEvent 事件,该方法在应用程序上下文被刷新时触发,该事件是 Spring 框架内置事件,由 Spring 框架执行到某一个时刻触发,我们就负责接收通知,这是其中一种观察者方式。

@Slf4j
@Component
public class SpringInitListener implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {if (event.getSource() instanceof AnnotationConfigServletWebServerApplicationContext) {if (log.isInfoEnabled()) {log.info("【SpringInitListener】Spring启动初始化监听,应用程序上下文已刷新~");}//执行主业务逻辑doBiz();}}/*** 执行业务逻辑*/private void doBiz() {}
}

使用 @EventListener 注解

该方式不需要继承或实现任何其他类,然后在它的某个方法上加上 @EventListener 注解,效果差不多。

@Slf4j
@Component
public class MySpringListener {@EventListener(ContextRefreshedEvent.class)public void methodA(ContextRefreshedEvent event) {if (log.isInfoEnabled()) {log.info("【MySpringListener】Spring启动初始化监听,应用程序上下文已刷新~");}}
}

Spring 常见内置事件

上面示例中,我们使用了一个 ContextRefreshedEvent 的事件,这个事件是Spring内置的事件,除了该事件,Spring还内置了一些其他的事件类型,分别在以下情况下触发。

Tips:不是很需要掌握全部的事件,按需使用。

SpringBoot Application 共支持6种事件监听,按顺序分别是:

  • ApplicationStartingEvent:在Spring最开始启动的时候触发
  • ApplicationEnvironmentPreparedEvent:在Spring已准备好上下文但是上下文尚未创建的时候触发
  • ApplicationPreparedEvent:在Bean定义加载之后、刷新上下文之前触发
  • ApplicationStartedEvent:在刷新上下文之后、调用application命令之前触发
  • ApplicationReadyEvent:在调用applicaiton命令之后触发
  • ApplicationFailedEvent:在启动Spring发生异常时触发

Spring 的5个标准事件:

  • 上下文更新事件(ContextRefreshedEvent):该事件会在ApplicationContext被初始化或者更新时发布。也可以在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。
  • 上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。
  • 上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。
  • 上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。
  • 请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。

自定义事件与监听器

就下面三个步骤,可以直接看代码,前面示例翻新一下:
Step1、建立继承自ApplicationEvent的自定义事件类;
Step2、使用@EventListener注解来实现监听;
Step3、发布事件;

@Slf4j
@Component
public class MySpringListener {/*** 监听Spring内置事件*/@EventListener(ContextRefreshedEvent.class)public void methodA(ContextRefreshedEvent event) {if (log.isInfoEnabled()) {log.info("【MySpringListener】Spring启动初始化监听,应用程序上下文已刷新~");}}/*** 监听自定义事件*/@EventListener(MyCustomEvent.class)public void methodB(MyCustomEvent event) {log.info("========我监听到自定义事件了:" + event.getMessage());}/*** 再次监听自定义事件*/@EventListener(MyCustomEvent.class)public void methodC(MyCustomEvent event) {log.info("========我监听到自定义事件了:" + event.getMessage());}
}@Getter
@Setter
public class MyCustomEvent extends ApplicationEvent {private String message;public MyCustomEvent(Object source, String message) {super(source);this.message = message;}
}@Slf4j
@Component
public class SpringInitListener implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {if (event.getSource() instanceof AnnotationConfigServletWebServerApplicationContext) {if (log.isInfoEnabled()) {log.info("【SpringInitListener】Spring启动初始化监听,应用程序上下文已刷新~");}// 发布自定义事件MyCustomEvent myCustomEvent = new MyCustomEvent(applicationContext, "这是自定义事件,我发布了");applicationContext.publishEvent(myCustomEvent);// 执行主业务逻辑doBiz();}}/*** 执行业务逻辑*/private void doBiz() {}
}

Spring 监听器原理分析

这里简单说一下Spring监听器的实现原理。
Spring 的监听器用到了观察者模式、工厂模式、适配器模式,以观察者模式为主,可用于松散耦合,改进代码管理和潜在的复用。
通俗来说,就是创建一个主题对象,主题对象维护一个观察者列表,当主题对象的状态发生变化时,它会遍历观察者列表,并调用每个观察者的通知方法。观察者接收到通知后,根据通知进行相应的更新操作。
举例说明,当抖音的某个海贼王博主,很多粉丝关注了它的海贼王专栏,就属于它的观察者,当博主更新了海贼王1100集漫画的讲解视频,这些粉丝在抖音在线的状态,会收到该视频的更新通知,可以快速点击进去,一睹为快。
这个模式其实很好理解,可能很多场景都遇到过它的变种。消息中心的事件驱动机制,Redis-Key的发布订阅机制,都是基于观察者模式扩展而来,运用范围相当广。
由于本篇文章是知识点扫盲系统,属于技术入门,后续企业实战或源码分析会详细展开。


实战 · 初始化监听器拓展

本来内容写到这边差不多了,但是感觉好像太少一些,实战部分的还是分享一些。
显然,这个用法很简单,关于 ContextRefreshedEvent 的初始化监听,作为具体某个模块的开发人员完全可以写一个 Spring 监听器类,完成自己想要的初始化动作,So easy~
但该用法存在一些局限性:
首先,该操作是同步的,若初始化执行的程序逻辑耗时较多,会影响整个服务的启动时长,进而引发一系列问题,例如KS8误判启动失败等;
其次,该操作中,只要业务逻辑存在未把控到位的情况,意外抛出了异常,那么将直接导致程序启动失败,这可能是违背初衷的;
总之,这两点因素带来的影响都很大,那么作为一个框架搭建人员,如何应对这些现象,如何给开发人员更灵活的编码体验,这个是需要我们思考的。
参考:《框架封装 · 自定义初始化事件》


其他监听器

除了上面介绍的 Spring 和 Servlet 之外,其他技术也有监听器,简单介绍一些,不展开。

1、JavaScript 监听器
JavaScript 广泛应用于前端开发,浏览器提供了多种事件监听机制。
关键词: addEventListener

2、Kafka 监听器
Apache Kafka 提供了事件监听机制,用于处理消息队列中的事件。

@KafkaListener(topics = "myTopic", groupId = "myGroup")
public void listen(String message) {System.out.println("Received message: " + message);
}

3、Hibernate 监听器
Hibernate 提供了事件监听器,用于监听实体对象的生命周期事件。

//PreInsertEventListener、PostInsertEventListener:监听实体插入事件。
public class MyPreInsertEventListener implements PreInsertEventListener {@Overridepublic boolean onPreInsert(PreInsertEvent event) {return false;}
}

总结陈词

上文介绍了监听器的用法,主要介绍了 Spring 监听器的用法,仅供参考。
监听器用的最多的场景,还是初始化监听器,程序启动之前执行一些诸如,数据加载到缓存等动作。
💗 后续企业实战或源码分析会详细展开。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/40384.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高效前端开发:解密pnpm的存储与链接

什么是pnpm PNPM&#xff08;Performant NPM&#xff09;是一种快速且节省磁盘空间的包管理工具。相较于其他包管理器如NPM和Yarn&#xff0c;PNPM通过独特的存储机制和链接技术解决了许多常见的问题。以下是PNPM如何避免这些问题以及其关键技术的详细介绍。 特性 PNPM Store…

批量注册工具是什么

摘要&#xff1a;批量注册工具作为自动化领域的一个分支&#xff0c;为用户在多平台账号管理中提供了极大的便利。 关键词 批量注册&#xff0c;自动化&#xff0c;实战代码&#xff0c;设计原则&#xff0c;法律法规 1. 引言 批量注册工具能够在短时间内创建大量账号&…

【MySQL备份】Percona XtraBackup总结篇

目录 1.前言 2.问题总结 2.1.为什么在恢复备份前需要准备备份 2.1.1. 保证数据一致性 2.1.2. 完成崩溃恢复过程 2.1.3. 解决非锁定备份的特殊需求 2.1.4. 支持增量和差异备份 2.1.5. 优化恢复性能 2.2.Percona XtraBackup的工作原理 3.注意事项 1.前言 在历经了详尽…

数据库、创建表、修改表

一、数据库 1、登陆数据库 2、创建数据库zoo 3、修改数据库zoo字符集为gbk 4、选择当前数据库为zoo 5、查看创建数据库zoo信息 6、删除数据库zoo 二、创建表 1、创建一个名称为db_system的数据库 2、在该数据库下创建两张表&#xff0c;具体要求如下 员工表 user…

图像的对数变换

对数变换在图像处理中通常有以下作用&#xff1a; 因为对数曲线在像素值较低的区域斜率较大&#xff0c;像素值较高的区域斜率比较低&#xff0c;所以图像经过对数变换之后&#xff0c;在较暗的区域对比度将得到提升&#xff0c;因而能增强图像暗部的细节。图像的傅里叶频谱其…

MySQL 结构的优化方案

主要是指三方面&#xff0c;即表结构、字段结构以及索引结构&#xff0c;这些结构如果不合理&#xff0c;在某些场景下也会影响数据库的性能&#xff0c;因此优化时也可以从结构层面出发。一般在项目的库表设计之初就要考虑&#xff0c;当性能瓶颈出现时再调整结构&#xff0c;…

Python函数语法详解(与C++对比学习)【未完】

一、Python函数的形式 def function_name (参数, ...) -> return value_type:# 函数体return value# 看具体需求# 如果没有return语句&#xff0c;函数执行完毕后也会返回结果# 只是结果为None。return None可以简写为return 1. Python的返回值 在Python3中&#xff0c;提…

利用Redis bitmap 实现签到案例

数据库实现 设计签到功能对应的数据库表 CREATE TABLE sign_record (id bigint NOT NULL AUTO_INCREMENT COMMENT 主键,user_id bigint NOT NULL COMMENT 用户id,year year NOT NULL COMMENT 签到年份,month tinyint NOT NULL COMMENT 签到月份,date date NOT NULL COMMENT 签…

EI检索被认为是工程技术领域的权威数据库

EI检索被认为是工程技术领域的权威数据库&#xff0c;能够被EI检索收录的期刊和会议论文通常被认为具有一定的学术质量和影响力。然而&#xff0c;EI检索与“高水平”不能完全画等号&#xff0c;以下是一些需要考虑的因素&#xff1a; 1. 收录标准&#xff1a;虽然EI检索有严格…

在Linux操作系统中关于逻辑卷的案例

1.如何去创建一个逻辑卷 1.1先去创建物理卷 如上图所示&#xff0c;physical volume 物理卷 被成功创建。 如上图所示&#xff0c;可以使用pvscan来去查看当前Linux操作系统的物理卷/ 1.2使用创建好的物理卷去创建一个卷组。 如上图所示&#xff0c;可以使用第一步创建的两个…

【中项第三版】系统集成项目管理工程师 | 第 9 章 项目管理概论③ | 9.6 - 9.10

前言 第 9 章对应的内容选择题和案例分析都会进行考查&#xff0c;这一章节理论性较强&#xff0c;学习要以教材为准。本章分值预计在4-5分。 目录 9.6 项目管理过程组 9.7 项目管理原则 9.8 项目管理知识领域 9.9 价值交付系统 9.10 本章练习 9.6 项目管理过程组 项目…

千万不能踏入的渠道管理五大误区!【附策略】

一、引言 在当今激烈的市场竞争环境中&#xff0c;有效的渠道管理是企业获得竞争优势的关键。然而&#xff0c;在实践过程中&#xff0c;不少企业因陷入管理误区而影响了市场拓展和品牌建设。本文旨在揭示渠道管理中常见的五大误区&#xff0c;并提供避免策略&#xff0c;帮助…

高级Redis之Stream的用法示例

不想自己搭建一个mq怎么办&#xff1f;Redis的Stream 来帮你&#xff0c;Redis Stream 是 Redis 5.0 引入的一种新的数据结构&#xff0c;用于处理实时的、可持久化的、基于时间序列的数据流。它非常适合处理事件流、日志、消息队列等场景。下面是一个使用 Redis Stream 的具体…

web基础与HTTP协议(企业网站架构部署与优化)

补充&#xff1a;http服务首页文件在/var/www/html下的&#xff0c;一定是index.html命名的文件。才会显示出来。 如果该路径下没有相应的文件&#xff0c;会显示/usr/share/httpd/noindex下的index.html文件。 如果/usr/share/httpd/noindex没有index.html文件&#xff0c;会…

BSI 第七届万物互联智慧高峰论坛:主题:拥抱AI时代,标准赋能组织实现可持续发展

BSI 第七届万物互联智慧高峰论坛&#xff1a;主题&#xff1a;拥抱AI时代&#xff0c;标准赋能组织实现可持续发展 主要收到 BSI 温女士的邀请参加的本次论坛。还是学到的很多 。 在科技日新月异的时代背景下&#xff0c;BSI 第七届万物互联智慧高峰论坛于[时间&#xff1a;6…

Object 类中的公共方法详解

Object 类中的公共方法详解 1、clone() 方法2、equals(Object obj) 方法3、hashCode() 方法4、getClass() 方法5、wait() 方法6、notify() 和 notifyAll() 方法 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在 Java 中&#xff0c;Object…

AI 驱动的数据中心变革与前景

文章主要探讨了AI计算时代数据中心的转型&#xff0c;涉及计算技术的多样性、规格尺寸和加速器的发展、大型语言模型&#xff08;LLM&#xff09;的发展、功耗和冷却趋势、基准测试的重要性以及数据中心的发展等方面。为大家提供深入了解AI基础设施发展的视角。 计算技术的多样…

Ubuntu(通用)—网络加固—ufw+防DNS污染+ARP绑定

1. ufw sudo ufw default deny incoming sudo ufw deny in from any to any # sudo ufw allow from any to any port 5353 protocol udp sudo ufw enable # 启动开机自启 # sudo ufw reload 更改后的操作2. 防ARP欺骗 华为云教程 arp -d删除dns记录arp -a显示arp表 ipconfi…

PTrade常见问题系列3

量化允许同时运行回测和交易的策略个数配置。 量化允许同时运行回测和交易的策略个数在哪里查看&#xff1f; 在量化服务器/home/fly/config/custom_config_conf文件中&#xff0c;其中运行回测的策略个数由backtest_switch&#xff08;是否限制普通回测个数&#xff09;及ba…

Qt 日志输出的选择方案有多少

Qt 日志输出的选择方案主要包括以下几种&#xff1a; 使用内置的日志函数&#xff1a; qDebug()&#xff1a;用于输出调试信息。qInfo()&#xff1a;用于输出一般信息。qWarning()&#xff1a;用于输出警告信息。qCritical()&#xff1a;用于输出关键错误信息&#xff0c;表明…