springboot监听器的使用(ApplicationListenerSmartApplicationListener@EventListener)
Posted 364.99°
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot监听器的使用(ApplicationListenerSmartApplicationListener@EventListener)相关的知识,希望对你有一定的参考价值。
目录
前言
监听器: 当某个事件触发的时候,就会执行的方法块。
springboot提供了两个接口来实现监听:ApplicationListener、SmartApplicationListener,如下图。显而易见,SmartApplicationListener 是 ApplicationListener 的子类,故而其功能要强于 ApplicationListener。
当然,springboot很贴心地提供了一个 @EventListener 注解来实现监听。
1. ApplicationListener
1. 简单的全局监听
首先,先来简单体验一下监听器的功能。
需求: 在spring容器初始化完成之后就开始监听,并打印日志。
实现:
-
准备springboot工程(依赖:springboot、lombok)
-
写一个监听器
@Slf4j @Component public class MyTask implements ApplicationListener<ContextRefreshedEvent> private static boolean aFlag = false; @Override public void onApplicationEvent(ContextRefreshedEvent event) if (!aFlag) aFlag = true; log.info("我已经监听到了");
-
启动项目,控制台输出如下:
现在来说一下为什么要这么写监听器:
-
实现接口
implements ApplicationListener<ContextRefreshedEvent>
自定义监听器需要实现 ApplicationListener<E extends ApplicationEvent> 接口
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<ContextRefreshedEvent> 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会自动被通知。
先来看一下 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<? extends ApplicationEvent> 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<ApplicationEvent>, Ordered
boolean supportsEventType(Class<? extends ApplicationEvent> 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)
以上是关于springboot监听器的使用(ApplicationListenerSmartApplicationListener@EventListener)的主要内容,如果未能解决你的问题,请参考以下文章
基于Springboot搭建java项目(二十三)——SpringBoot使用过滤器拦截器和监听器
SpringBoot监听器ApplicationListener的使用-监听ApplicationReadyEvent事件
springboot监听器的使用(ApplicationListenerSmartApplicationListener@EventListener)
springboot监听器的使用(ApplicationListenerSmartApplicationListener@EventListener)