首页 > 其他分享 >springboot监听器的使用(ApplicationListener、SmartApplicationListener、@EventListener)

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

时间:2024-10-25 17:46:46浏览次数:1  
标签:ApplicationListener SmartApplicationListener class 打印 监听 event MyEvent 监听器 publi

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

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

  

目录

 

前言

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

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会自动被通知。

参考链接: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<? 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})

__________________________________________________________________________________________

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

  

标签:ApplicationListener,SmartApplicationListener,class,打印,监听,event,MyEvent,监听器,publi
From: https://www.cnblogs.com/kelelipeng/p/18503008

相关文章

  • Spring 过滤器 拦截器 监听器 Aop
    目录Spring过滤器拦截器监听器Aop1.过滤器2.拦截器3.监听器4.Aop5.参考文档Spring过滤器拦截器监听器Aop1.过滤器1.简介 过滤器Filter用于对数据进行过滤和预处理 过滤器只能在请求前后使用 依赖于servlet容器基于函数回调实现其生命周期由servlet容器管......
  • Filter 过滤器和 Listener 监听器
    2、开发步骤3、过滤器执行流程4、过滤器生命周期5、过滤器配置问题6、过滤器链(配置多个过滤器)二、Listener监听器1、ServletContextListener接口2、开发步骤一、Filter过滤器============1、概述当访问服务器资源时,Filter过滤器可以将请求拦截下来,完成一些特殊的......
  • flowable 流程动态设置监听器(非xml中定义)及发起时从驳回节点开始审批实现
    一、flowable使用代码动态修改监听器1、配置类@ConfigurationpublicclassFlowableGlobListenerConfig{@Lazy@AutowiredprivateTaskStartListenertaskStartListener;@Lazy@AutowiredprivateTaskCompleteListenertaskCompletedListener;......
  • class 4: vue.js 3监听器 watch
    某些情况下需要监听某个响应式数据的变化,这时就需要使用监听器(watch)来实现了watch的使用语法如下选项:watch类型:{[key:string]:string|Function|Object|Array}详解:watch属性是一个对象,该对象的键(key)是需要观察的表达式,值(value)可以是回调函数、方法名等。Vu......
  • java牛马之路22-Listener监听器
    监听器概念监听器用于监听web应用中某些对象信息的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等。创......
  • 详细了解Servlet中过滤器和监听器的使用
    目录一、过滤器1.1概念1.2过滤器的实现1.3过滤器中方法的介绍1.4过滤器的执行过程二、监听器2.1概念2.2 监听器的实现2.3不同监听器接口的介绍1. ServletContextListener接口2. HttpSessionListener接口3. HttpSessionAttributeListener接口一、过滤......
  • SpringBoot中使用监听器
    1.定义一个事件/***定义事件*@authorhrui*@date2024/7/2512:46*/publicclassCustomEventextendsApplicationEvent{privateStringmessage;publicCustomEvent(Objectsource,Stringmessage){super(source);this.message......
  • SpringBoot源码初学者(二):SpringBoot事件监听器
    ps:真正适合阅读源码的新手来看的SpringBoot源码讲解,如果你真的想读懂SpringBoot源码,可以按照以下推荐的方式来阅读文章打开ide,打开SpringBoot源码,跟着文章一起写注释,写自己的注释不要过于纠结没讲到的地方,毕竟SpringBoot源码那么多,想全讲完是不可能的,只要跟着文章认真阅......
  • JavaWed过滤器和监听器(知识回顾+详解)
    过滤器 Filter   1.1概念       在浏览器和目标资源之间进行过滤的中间组件。       请求到达目标资源之前进行过滤。       响应到达浏览器之前进行过滤。   1.2定义过滤器的步骤      1.写一个java类,实现Filter接口   ......
  • 【Flowable | 第三篇】flowable工作流使用任务监听器、执行监听器
    文章目录4.flowable工作流使用任务监听器、执行监听器4.1任务监听器4.2执行监听器4.2配置任务/执行监听器4.2.1新增任务监听器4.2.2新增执行监听器4.2.2任务节点配置任务/执行监听器(1)选择类的类型(2)使用表达式类型(3)使用委托表达式4.3测试4.4小结4.flowable工作流使......