Spring及SpringBoot的事件监听Demo案例

前置

推送事件并实现监听。

项目源码地址:https://gitee.com/changluJava/demo-exer/tree/master/SpringDemo/spring-event


基础概念

在spring中,包含有事件机制,首先有一个发布事件A,接着有一个监听器B可以自动去监听这个发布事件的发布,在整个过程有3个对象:

  1. 事件本身,其实就是一个对象,这个对象对应的类要继承spring的ApplicationEvent,这样才能被spring识别。
  2. 发布事件的对象,一般都是使用ApplicationContext的publishEvent方法来发布;(对于springboot,可以通过注入形式获取)
  3. 接收(或者叫监听)事件的对象,使用onApplicationEvent方法或者使用@EventListener注解的方法;

对于SpringBoot项目,如何获取到Spring容器?

@Autowired
private ApplicationContext applicationContext;

Spring事件监听:基础实战案例

前提准备

image-20240328152128385

配置spring依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.2</version>
    </dependency>
</dependencies>

①自定义Spring配置类:SpringConfig

package com.changlu.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @description  Spring配置类
 * @author changlu
 * @date 3/28/2024 3:10 PM
 * @version 1.0
 */
@Configuration
@ComponentScan("com.changlu")
public class SpringConfig {
}

②事件定义:MyEvent

自定义的事件需要继承ApplicationEvent,才能够作为一个事件:

package com.changlu;
import org.springframework.context.ApplicationEvent;

/**
 * @description  MyEvent 事件
 * @author changlu
 * @date 3/28/2024 3:10 PM
 * @version 1.0
 */
public class MyEvent extends ApplicationEvent {

    private String name;

    public MyEvent(Object source, String  name) {
        super(source);
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

③事件监听器:MyEventListener

实现指定的ApplicationListener监听器接口,并且配置好之前定义的事件:

package com.changlu;

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * @author changlu
 * @version 1.0
 * @description MyEvent事件Listener监听器
 * @date 2024/03/28 15:06
 */
@Component
public class MyEventListener implements ApplicationListener<MyEvent> {
    @Override
    public void onApplicationEvent(MyEvent event) {
        //可以拿到这个对象,可以使用到其中的相应的事件对象
        System.out.println("名字叫做:" + event.getName());
    }
}

测试类Main

初始化spring容器,接着我们在容器中发布一个事件:

package com.changlu;

import com.changlu.config.SpringConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author changlu
 * @version 1.0
 * @description 手动获取spring容器,接着发布事件
 * @date 2024/03/28 14:44
 */
public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        //发布事件,指定的事件为:EventTest
        context.publishEvent(new MyEvent(context, "changlu"));
    }
}

效果:可以看到当我们进行发布的时候,此时就会在相应的监听器中执行相应的业务逻辑。

image-20240328152437465


SpringBoot的Application事件监听的实现方案

基础知识

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

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

另外:

  • ApplicationRunner和CommandLineRunner的执行在第五步和第六步之间
  • Bean的创建在第三步和第四步之间
  • 在启动类中,执行SpringApplication.run()方法后的代码,会在第六步后执行

前提准备

①环境与准备事件监听器:ApplicationEnvironmentPreparedEventListener

package com.changlu.listeners;

import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;

/**
 * @author changlu
 * @version 1.0
 * @description ApplicationEnvironmentPreparedEvent 事件监听器
 * @date 2024/03/28 15:37
 */
//@Component
public class ApplicationEnvironmentPreparedEventListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        System.out.println("============>>>>> ApplicationEnvironmentPreparedEvent is trigged");
        System.out.println(event.getTimestamp());
        System.out.println("============>>>>> End");
    }
}

②应用预准备事件监听器:ApplicationPreparedEventListener

package com.changlu.listeners;

import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.context.ApplicationListener;

/**
 * @author changlu
 * @version 1.0
 * @description ApplicationPreparedEvent 事件监听器
 * @date 2024/03/28 15:41
 */
//@Component
public class ApplicationPreparedEventListener implements ApplicationListener<ApplicationPreparedEvent> {
    @Override
    public void onApplicationEvent(ApplicationPreparedEvent event) {
        System.out.println("============>>>>> applicationPreparedEvent is trigged");
        System.out.println(event.getTimestamp());
        System.out.println("============>>>>> End");
    }
}

③应用启动事件监听器:ApplicationStartedEventListener(刷新上下文后)

package com.changlu.listeners;

import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;

/**
 * @author changlu
 * @version 1.0
 * @description ApplicationStartedEvent 事件监听器
 * @date 2024/03/28 15:42
 */
//@Component
public class ApplicationStartedEventListener implements ApplicationListener<ApplicationStartedEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        System.out.println("============>>>>> applicationStartedEvent is trigged");
        System.out.println(event.getTimestamp());
        System.out.println("============>>>>> End");
    }
}

④应用启动事件中监听器:ApplicationStartingEventListener

package com.changlu.listeners;

import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;

/**
 * @author changlu
 * @version 1.0
 * @description ApplicationStartedEvent 事件监听器
 * @date 2024/03/28 15:35
 */
//@Component
public class ApplicationStartingEventListener implements ApplicationListener<ApplicationStartedEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        System.out.println("============>>>>> applicationStartingEvent is trigged");
        System.out.println(event.getTimestamp());
        System.out.println("============>>>>> End");
    }
}

⑤应用准备事件监听器:ApplicationReadyEventListener

package com.changlu.listeners;

import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;

/**
 * @author changlu
 * @version 1.0
 * @description ApplicationReadyEvent 事件监听器
 * @date 2024/03/28 15:43
 */
//@Component
public class ApplicationReadyEventListener implements ApplicationListener<ApplicationReadyEvent> {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        System.out.println("============>>>>> applicationReadyEvent is trigged");
        System.out.println(event.getTimestamp());
        System.out.println("============>>>>> End");
    }
}

⑥应用失败监听器:ApplicationFailedEventListener

package com.changlu.listeners;

import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.context.ApplicationListener;

/**
 * @author changlu
 * @version 1.0
 * @description ApplicationFailedEvent 事件监听器
 * @date 2024/03/28 15:44
 */
//@Component
public class ApplicationFailedEventListener implements ApplicationListener<ApplicationFailedEvent> {
    @Override
    public void onApplicationEvent(ApplicationFailedEvent event) {
        System.out.println("============>>>>> ApplicationFailedEvent is trigged");
        System.out.println(event.getTimestamp());
        System.out.println("============>>>>> End");
    }
}

启动器添加监听器

package com.changlu;

import com.changlu.listeners.*;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author changlu
 * @version 1.0
 * @description SpringBoot启动类
 * @date 2024/03/28 15:33
 */
@SpringBootApplication
public class SpringBootEvent {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(SpringBootEvent.class);
        springApplication.addListeners(new ApplicationEnvironmentPreparedEventListener());
        springApplication.addListeners(new ApplicationFailedEventListener());
        springApplication.addListeners(new ApplicationPreparedEventListener());
        springApplication.addListeners(new ApplicationReadyEventListener());
        springApplication.addListeners(new ApplicationStartedEventListener());
        springApplication.addListeners(new ApplicationStartingEventListener());
        springApplication.run(args);
    }
}

image-20240328160406764

若是将这么多事件以注解形式创建bean到容器当中,此时springboot启动的时候只会触发这三个事件监听器:

image-20240328163906367

说明:在我司项目中主要使用到了ApplicationStartedEvent事件,只需要知道它是在在刷新上下文之后、调用application命令之前触发(此时应该是所有的bean实例都已经加载完成了)。


参考资料

[1]. spring的事件机制onApplicationEvent(非注解)和@EventListener(注解):https://blog.csdn.net/jeffersonchern/article/details/125559289


整理者:长路 时间:2024.3.28

评论区请在客户端页面查看