一、前言
需要实现spring boot自定义事件的发布与监听,其实并没有多复杂,可以分以下三步进行:
- 通过继承抽象类ApplicationEvent,自定义事件;
- 通过实现 ApplicationListener接口 或者通过 @EventListener 注解到方法上,自定义一个事件的监听;
- 通过ApplicationContext对象,发布事件。
二、代码实现
- 创建一个spring boot项目,项目结构如下:
2. 导入maven依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
- 自定义一个事件类,继承ApplicationEvent抽象类:
/**
* 自定义一个事件
*/
@Getter
public class MyEvent extends ApplicationEvent {
String name;
public MyEvent(Object source, String name) {
super(source);
this.name = name;
}
}
- 自定义一个事件的监听类,实现ApplicationListener接口,并且将监听类注册到spring容器中:
/**
* 定义一个自定义事件的监听
*/
@Component
@Slf4j
public class MyListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
log.info(new StringBuilder()
.append(event.getName())
.append("在")
.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
.append("访问了系统!")
.toString());
}
}
- 测试,为了方便,创建一个TestController进行测试:
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
// 注入ApplicationContext对象
@Autowired
ApplicationContext applicationContext;
@GetMapping("login")
public String loginTest(String name) {
// 发布事件
applicationContext.publishEvent(new MyEvent(this, name));
// 日志记录
log.info(new StringBuilder()
.append(name)
.append("在")
.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
.append("登录成功!")
.toString());
// 返回结果
return name + " login success!";
}
}
运行项目,访问http://localhost:8080/test/login?name=张三,运行结果:
可以看到发布的事件成功被监听到了。
@EventListener注解的使用
上面实现监听类的方式是实现ApplicationListener接口,除此之外还可以在方法上使用@EventListener注解,重新实现MyListener ,代码如下:
@Component
@Slf4j
public class MyListener {
@EventListener
public void handlerMyEvent(MyEvent event) {
log.info(new StringBuilder()
.append(event.getName())
.append("在")
.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
.append("访问了系统!")
.toString());
}
}
再次访问,运行结果:
可以看到,结果都可以成功监听到发布的事件。
异步进行事件监听
可以看到,就上面的例子来说,通知张三访问了系统和张三成功登录是没有串联关系的,这个通知事件可以异步进行。
- 启动类上添加@EnableAsync注解,开启异步调用:
@SpringBootApplication
@EnableAsync
public class SpringbootEventApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootEventApplication.class, args);
}
}
- 在监听方法上添加@Async注解:
@Component
@Slf4j
public class MyListener {
@EventListener
@Async // 异步执行
public void handlerMyEvent(MyEvent event) {
log.info(new StringBuilder()
.append(event.getName())
.append("在")
.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
.append("访问了系统!")
.toString());
}
}
运行结果:
可以看到发布的事件是用另外的线程异步执行的。