一、简介
Spring Boot事件监听器(Event Listener)用于在应用程序的生命周期中,监听Spring Boot应用程序中各种事件的发生,以便在事件发生时执行某些特定的操作。
二、集成步骤
1、创建自定义事件类
package cn.ddcherry.springboot.demo.event;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;
@Getter
public class CustomEvent extends ApplicationEvent {
private String message;
public CustomEvent(Object source, String message) {
super(source);
this.message = message;
}
}
这里笔者汪小成创建了一个简单的事件类,继承了org.springframework.context.ApplicationEvent
,事件类只有一个 String 类型的消息属性。
事件类不是必须继承
ApplicationEvent
,一个普通的类也可以作为一个事件类。
2、创建事件监听器
创建一个监听器类并实现ApplicationListener
接口,该接口有一个onApplicationEvent()
方法,用于处理事件:
package cn.ddcherry.springboot.demo.listener;
import cn.ddcherry.springboot.demo.event.CustomEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
log.info("事件监听器 - 收到消息:{}", event.getMessage());
}
}
在上面的代码中,CustomEventListener
实现了ApplicationListener<CustomEvent>
接口,并且实现了onApplicationEvent
方法。当一个CustomEvent
事件被发布时,onApplicationEvent
方法将被自动调用。
在CustomEventListener
上使用@Component
注解,将其作为 Spring 组件进行注册。
创建事件监听器有两种方式:
(1) 实现ApplicationListener
接口;
(2) 使用@EventListener
注解,@EventListener
注解可以直接在方法上使用,以指定该方法为事件监听器。
@Component
public class CustomEventListener {
@EventListener
public void handleMyEvent(CustomEvent event) {
//处理事件
}
}
3、创建事件发布者
package cn.ddcherry.springboot.demo.publisher;
import cn.ddcherry.springboot.demo.event.CustomEvent;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@AllArgsConstructor
public class CustomEventPublisher {
private ApplicationEventPublisher publisher;
public void publish(String message) {
CustomEvent customEvent = new CustomEvent(this, message);
publisher.publishEvent(customEvent);
log.info("事件发布成功 - 消息:{}", message);
}
}
上面的示例中,通过构造方法注入的方式自动注入ApplicationEventPublisher
,然后在方法内部调用了ApplicationEventPublisher
的publishEvent(...)
方法发布了一个自定义事件CustomEvent
。
4、创建测试控制器类
为了演示事件监听,我们创建了一个控制器。代码如下:
package cn.ddcherry.springboot.demo.controller;
import cn.ddcherry.springboot.demo.publisher.CustomEventPublisher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/event")
public class EventController {
@Resource
private CustomEventPublisher customEventPublisher;
@GetMapping("/publish")
public Map<String, Object> publish(@RequestParam("message") String message) {
customEventPublisher.publish(message);
Map<String, Object> resultMap = new HashMap<>(16);
resultMap.put("data", "事件发布成功");
resultMap.put("message", message);
return resultMap;
}
}
5、测试
启动spring Boot项目,然后在浏览器地址栏输入http://localhost:8080/event/publish?message=嗨皮汪小成
,在控制台我们可以看到如下输出内容:
事件监听器 - 收到消息:嗨皮汪小成
事件发布成功 - 消息:嗨皮汪小成
异步处理事件
默认情况下,Spring Boot 事件监听器会同步处理事件。也就是说,当事件触发时,Spring Boot 事件监听器会在同一个线程中处理该事件。这种处理方式的好处是可以保证处理事件的顺序和一致性,但如果事件处理比较耗时,可能会阻塞主线程。
Spring Boot 提供了异步处理事件的方式。可以通过在事件监听器上加上 @Async
注解来实现异步处理事件。同时还要在项目启动类上添加@EnableAsync
注解来开启异步执行器的支持。
1、创建异步事件监听器
package cn.ddcherry.springboot.demo.listener;
import cn.ddcherry.springboot.demo.event.CustomEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Slf4j
@Async
@Component
public class CustomAsyncEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
log.info("事件监听器(异步) - 收到消息:{},开始处理。", event.getMessage());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("事件监听器(异步) - 处理完成!");
}
}
从上面的代码可以看出,笔者汪小成在事件监听器上加上 @Async
注解来实现异步处理事件,使用Thread.sleep(2000)
模拟监听器处理事件耗时。
2、在项目启动类上添加@EnableAsync
注解
package cn.ddcherry.springboot.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
+ @EnableAsync
@SpringBootApplication
public class EventApplication {
public static void main(String[] args) {
SpringApplication.run(EventApplication.class, args);
}
}
3、测试
启动spring Boot项目,然后在浏览器地址栏输入http://localhost:8080/event/publish?message=嗨皮汪小成
,在控制台我们可以看到如下输出内容:
事件监听器(异步) - 收到消息:嗨皮汪小成,开始处理。
事件发布成功 - 消息:嗨皮汪小成
事件监听器(异步) - 处理完成!
总结
使用事件的好处是解耦,可以方便地实现模块间的通信,同时也可以提高代码的可读性和可维护性。
项目源码地址:https://github.com/wanggch/spring-boot-demos/tree/main/05.spring-boot-event
Spring Boot系列文章
- Spring Boot | 手动创建多模块项目
- Spring Boot | 手动创建一个简单的Spring Boot项目
- Spring Boot | 集成Thymeleaf模板引擎
- Spring Boot | 整合Swagger、Knife4j自动生成API文档
- Spring Boot| 集成MapStruct实现不同类型Java对象间的自动转换