springboot监听器的使用(ApplicationListener、SmartApplicationListener、@EventListener)

springboot监听器的使用(ApplicationListener、SmartApplicationListener、@EventListener)

Springboot监听器的使用(ApplicationListener、SmartApplicationListener、@EventListener)

https://blog.csdn.net/m0_54355172/article/details/128592476

目录

前言

1. ApplicationListener

1. 简单的全局监听

2. 定时任务

3. 监听自定义事件

2. SmartApplicationListener

1. 简单使用

2. 方法介绍

3. @EventListener

前言

监听器: 当某个事件触发的时候,就会执行的方法块。

springboot提供了两个接口来实现监听:ApplicationListener、SmartApplicationListener,如下图。显而易见,SmartApplicationListener 是 ApplicationListener 的子类,故而其功能要强于 ApplicationListener。

当然,springboot很贴心地提供了一个 @EventListener 注解来实现监听。

1. ApplicationListener

1. 简单的全局监听

首先,先来简单体验一下监听器的功能。

需求: 在spring容器初始化完成之后就开始监听,并打印日志。

实现:

准备springboot工程(依赖:springboot、lombok)

写一个监听器

@Slf4j

@Component

public class MyTask implements ApplicationListener {

private static boolean aFlag = false;

@Override

public void onApplicationEvent(ContextRefreshedEvent event) {

if (!aFlag) {

aFlag = true;

log.info("我已经监听到了");

}

}

}

启动项目,控制台输出如下:

现在来说一下为什么要这么写监听器:

实现接口

implements ApplicationListener

自定义监听器需要实现 ApplicationListener 接口

ContextRefreshedEvent 是一个事件,它会在 spring容器初始化完成 之后被触发,所以监听器就会在 spring容器初始化完成之后开始监听,所以这就是所谓的全局监听

标志位 aFlag

private static boolean aFlag = false;

aFlag 是一个启动标志因为web应用会出现父子容器,这样就会触发两次监听任务,所以需要一个标志位,保证监听任务(log.info(“我已经监听到了”))只会触发一次

2. 定时任务需求: 实现一个定时任务,每间隔5秒、10秒、15秒、20秒、25秒、30秒、40秒、50秒、60秒,在控制台打印一次日志。

实现: 可通过多线程的方式实现

新建一个类 TimerRunner 继承 Runnable

5秒到60秒的间隔可以通过 枚举类实现

private enum TimerEnum {

// 第5秒打印

FIRST(1, 5 ),

// 第10秒打印

SECOND(2, 10),

// 第15秒打印

THIRD(3, 15),

// 第20秒打印

FOURTH(4, 20),

// 第25秒打印

FIFTH(5, 25),

// 第30秒打印

SIXTH(6, 30),

// 第40秒打印

SEVENTH(7, 40),

// 第50秒打印

EIGHTH(8, 50),

// 第60秒打印

NINTH(9, 60);

private Integer count;

private Integer time;

TimerEnum(Integer count, Integer time) {

this.count = count;

this.time = time;

}

public Integer getCount() {

return count;

}

public Integer getTime() {

return time;

}

}

TimeRunner 完整代码

@Slf4j

public class TimerRunner implements Runnable{

@Override

public void run() {

// 打印次数

int count = 1;

SimpleDateFormat dateFormat= new SimpleDateFormat("hh:mm:ss");

for (TimerEnum item: TimerEnum.values()) {

if (count == item.getCount()) {

if (count != 9) {

log.info("时间: " + dateFormat.format(new Date()) + "第 " + count + " 次打印,还剩余 " + (9 - count) + " 次完成打印");

count++;

} else {

log.info("最后一次打印");

log.info("已完成所有打印任务!");

}

}

try {

// TimeUnit来sleep,可读性更好

TimeUnit.SECONDS.sleep(item.getTime());

} catch (InterruptedException e) {

throw new RuntimeException(e);

}

}

}

private enum TimerEnum {

// 第5秒打印

FIRST(1, 5 ),

// 第10秒打印

SECOND(2, 10),

// 第15秒打印

THIRD(3, 15),

// 第20秒打印

FOURTH(4, 20),

// 第25秒打印

FIFTH(5, 25),

// 第30秒打印

SIXTH(6, 30),

// 第40秒打印

SEVENTH(7, 40),

// 第50秒打印

EIGHTH(8, 50),

// 第60秒打印

NINTH(9, 60);

private Integer count;

private Integer time;

TimerEnum(Integer count, Integer time) {

this.count = count;

this.time = time;

}

public Integer getCount() {

return count;

}

public Integer getTime() {

return time;

}

}

}

MyTask 代码

@Slf4j

@Component

public class MyTask implements ApplicationListener {

private static boolean aFlag = false;

@Override

public void onApplicationEvent(ContextRefreshedEvent event) {

if (!aFlag) {

aFlag = true;

new Thread(new TimerRunner()).start();

}

}

}

控制台输出:

3. 监听自定义事件

Spring的 ApplicationContext 提供了支持事件和代码中监听器的功能。我们可以创建bean用来监听在 ApplicationContext 中发布的事件。ApplicationEvent 类在 ApplicationContext 接口中处理的事件,如果一个bean实现了 ApplicationListener 接口,当一个 ApplicationEvent 被发布以后,bean会自动被通知。

参考链接:https://cloud.tencent.com/developer/article/1532994

先来看一下 spring的内置事件 :

内置事件: 参考链接: https://blog.csdn.net/liyantianmin/article/details/81017960

事件 说明ContextRefreshedEvent ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext接口中使用 refresh() 方法来发生。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用。ContextStartedEvent 当使用 ConfigurableApplicationContext (ApplicationContext子接口)接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序。ContextStoppedEvent 当使用 ConfigurableApplicationContext 接口中的 stop() 停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作。ContextClosedEvent 当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启。RequestHandledEvent 这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件。

自定义监听事件:

extends ApplicationEvent 自定义事件

public class MyEvent extends ApplicationEvent {

private String time = new SimpleDateFormat("hh:mm:ss").format(new Date());

private String msg;

public MyEvent(Object source, String msg) {

super(source);

this.msg = msg;

}

public MyEvent(Object source) {

super(source);

}

public String getTime() {

return time;

}

public void setTime(String time) {

this.time = time;

}

public String getMsg() {

return msg;

}

public void setMsg(String msg) {

this.msg = msg;

}

}

监听器

@Slf4j

@Component

public class MyTask implements ApplicationListener {

private static boolean aFlag = false;

@Override

public void onApplicationEvent(ApplicationEvent event) {

if (event instanceof ContextRefreshedEvent) {

log.info("监听到 ContextRefreshedEvent...");

}

if (event instanceof MyEvent) {

log.info("监听到 MyEvent...");

MyEvent myEvent = (MyEvent) event;

System.out.println("时间:" + myEvent.getTime() + " 信息:" + myEvent.getMsg());

}

}

}

触发事件自定义监听事件需要主动触发

@SpringBootApplication

public class TaskApplication {

public static void main(String[] args) {

ConfigurableApplicationContext run = SpringApplication.run(TaskApplication.class, args);

MyEvent event = new MyEvent("event", "忙中岁月忙中遣,我本愚来性不移");

// 发布事件

run.publishEvent(event);

}

}

也可以这样触发,美观一点

@SpringBootApplication

public class TaskApplication implements CommandLineRunner {

public static void main(String[] args) {

SpringApplication.run(TaskApplication.class, args);

}

@Resource

private ApplicationContext applicationContext;

@Override

public void run(String... args) throws Exception {

MyEvent event = new MyEvent("event", "忙中岁月忙中遣,我本愚来性不移");

// 发布事件

applicationContext.publishEvent(event);

}

}

控制台输出

2. SmartApplicationListener

1. 简单使用

@Slf4j

@Component

public class MyTask implements SmartApplicationListener {

@Override

public boolean supportsEventType(Class eventType) {

return eventType == MyEvent.class || eventType == ContextRefreshedEvent.class;

}

@Override

public int getOrder() {

return 0;

}

@Override

public void onApplicationEvent(ApplicationEvent event) {

if (event instanceof ContextRefreshedEvent) {

log.info("监听到 ContextRefreshedEvent...");

}

if (event instanceof MyEvent) {

log.info("监听到 MyEvent...");

MyEvent myEvent = (MyEvent) event;

System.out.println("时间:" + myEvent.getTime() + " 信息:" + myEvent.getMsg());

}

}

}

2. 方法介绍

public interface SmartApplicationListener extends ApplicationListener, Ordered {

boolean supportsEventType(Class eventType);

default boolean supportsSourceType(@Nullable Class sourceType) {

return true;

}

@Override

default int getOrder() {

return LOWEST_PRECEDENCE;

}

default String getListenerId() {

return "";

}

}

方法 说明

supportsEventType 确认当前监听器是否支持当前事件类型。supportsSourceType 确定此监听器是否实际支持给定的源类型。getOrder 确定此侦听器在同一事件的一组侦听器中的顺序。数值越小,优先级越高。getListenerId 返回侦听器的可选标识符。

3. @EventListener使用:

@Slf4j

@Component

public class MyTask {

@EventListener

public void onApplicationEvent(ApplicationEvent event) {

if (event instanceof ContextRefreshedEvent) {

log.info("监听到 ContextRefreshedEvent...");

}

if (event instanceof MyEvent) {

log.info("监听到 MyEvent...");

MyEvent myEvent = (MyEvent) event;

System.out.println("时间:" + myEvent.getTime() + " 信息:" + myEvent.getMsg());

}

}

}

@Slf4j

@Component

public class MyTask {

@EventListener

public void MyEventListener(MyEvent event) {

log.info("监听到 MyEvent...");

MyEvent myEvent = (MyEvent) event;

System.out.println("时间:" + myEvent.getTime() + " 信息:" + myEvent.getMsg());

}

@EventListener

public void ContextRefreshedEventListener(MyEvent event) {

log.info("监听到 ContextRefreshedEvent...");

}

}

指定监听事件的类型:

@EventListener(MyEvent.class)

@EventListener({MyEvent.class, ContextRefreshedEvent.class})

__________________________________________________________________________________________

原文链接:https://blog.csdn.net/m0_54355172/article/details/128592476

🔮 相关作品

微信怎么发送小视频
365bet平台规则

微信怎么发送小视频

📅 07-28 👁️‍🗨️ 2620
指甲油怎么涂均匀
365bet平台规则

指甲油怎么涂均匀

📅 08-29 👁️‍🗨️ 5801
世界杯第一“毒奶”的含义及出处
365bet足球外围

世界杯第一“毒奶”的含义及出处

📅 07-21 👁️‍🗨️ 1794