springboot publish event 事件机制demo分享
作者:阿拉的梦想 发布时间:2022-11-19 23:45:45
1. 使用ApplicationEventPublisher 发布事件
复制下面全部代码,右键包名,粘贴即可生成java类,执行即可看到效果。
事件机制
需要自定义一个事件类继承ApplicationEvent;
需要自定义一个 * 类实现ApplicationListener接口,或普通类的方法中使用@EventListener注解;
使用默认发布器ApplicationEventPublisher发布即可;
事件类不需要注入到IOC; * 需要注入到IOC;ApplicationEventPublisher用Autowired注入进来即可;
默认情况下,事件发布与执行是同步的,事件执行完毕,发布者才会执行下面的逻辑;
package com.example.controller;
import com.alibaba.fastjson.JSON;
import com.example.SpringbootRedisApplication;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Objects;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SpringbootRedisApplication.class)
@Slf4j
@EnableAsync
public class PublishEventDemo {
/**
* 事件机制:
* 需要自定义一个事件类继承ApplicationEvent;
* 需要自定义一个 * 类实现ApplicationListener接口,或普通类的方法中使用@EventListener注解;
* 使用默认发布器ApplicationEventPublisher发布即可;
* 事件类不需要注入到IOC; * 需要注入到IOC;ApplicationEventPublisher用Autowired注入进来即可;
*/
/**
* 事件发布器
*/
@Autowired
private ApplicationEventPublisher eventPublisher;
/**
* 测试类
*/
@Test
public void publishTest() throws InterruptedException {
Task task = new Task();
task.setId(1L);
task.setTaskName("测试任务");
task.setTaskContext("任务内容");
task.setFinish(false);
MyEvent event = new MyEvent(task);
log.info("开始发布任务");
eventPublisher.publishEvent(event);
//applicationContext.publishEvent(event);
log.info("结束发布任务");
Thread.sleep(10000);
}
}
/**
* 任务类
* 任务就是一个普通的类,用来保存你要发布事件的内容。这个没有特殊限制,可以根据自己业务随意设置。
*/
@Data
class Task {
private Long id;
private String taskName;
private String taskContext;
private boolean finish;
}
/**
* 事件类
* 事件类需要继承org.springframework.context.ApplicationEvent,这样发布的事件才能被Spring所识别
*/
@Slf4j
class MyEvent<T> extends ApplicationEvent {
private Task task;
public MyEvent(Task task) {
super(task);
this.task = task;
}
public Task getTask() {
return task;
}
}
/**
* 事件监听类
* 事件的 * 需要实现org.springframework.context.ApplicationListener,并且需要注入到容器之中。
*/
@Component
@Slf4j
class MyEventListenerA implements ApplicationListener<MyEvent> {
/**
* 监听方式1:实现ApplicationListener接口,重写onApplicationEvent方法
* 需要使用Component注入IOC
*/
@SneakyThrows
@Async
@Override
public void onApplicationEvent(MyEvent MyEvent) {
Thread.sleep(5000);
if (Objects.isNull(MyEvent)) {
return;
}
Task task = MyEvent.getTask();
log.info(" * A接收任务:{}", JSON.toJSONString(task));
task.setFinish(true);
log.info(" * A此时完成任务");
}
}
@Component
@Slf4j
class MyEventListenerB implements ApplicationListener<MyEvent> {
/**
* 监听方式2:接口和注解混合使用
* 但此时 @EventListener不能与注解@Async在同一个类中使用,会报错,至于为什么,不知道;
* 需要使用Component注入IOC
*/
//@Async//加上这个,@EventListener的方法就会报java.lang.IllegalStateException: Failed to load ApplicationContext
@SneakyThrows
@Override
public void onApplicationEvent(MyEvent MyEvent) {
Thread.sleep(1000);
if (Objects.isNull(MyEvent)) {
return;
}
Task task = MyEvent.getTask();
log.info(" * B接收任务:{}", JSON.toJSONString(task));
task.setFinish(true);
log.info(" * B此时完成任务");
}
@EventListener
public void someMethod(MyEvent event) throws InterruptedException {
Thread.sleep(1000);
log.info(" * @EventListenerB收到={}", event.getTask());
}
}
@Component
@Slf4j
class MyEventListennerC {
/**
* 监听方式3:注解@EventListener的 * 不需要实现任何接口
* 需要使用Component注入IOC
*/
@EventListener
public void someMethod(MyEvent event) throws InterruptedException {
Thread.sleep(1000);
log.info(" * @EventListenerC收到={}", event.getTask());
}
}
运行日志:
2020-11-30 18:13:56.238 INFO 19776 --- [ main] com.example.controller.PublishEventDemo : Started PublishEventDemo in 11.098 seconds (JVM running for 13.737)
2020-11-30 18:13:56.902 INFO 19776 --- [ main] com.example.controller.PublishEventDemo : 开始发布任务
2020-11-30 18:13:57.904 INFO 19776 --- [ main] com.example.controller.MyEventListenerB : * @EventListenerB收到=Task(id=1, taskName=测试任务, taskContext=任务内容, finish=false)
2020-11-30 18:13:58.905 INFO 19776 --- [ main] c.example.controller.MyEventListennerC : * @EventListenerC收到=Task(id=1, taskName=测试任务, taskContext=任务内容, finish=false)
2020-11-30 18:13:59.920 INFO 19776 --- [ main] com.example.controller.MyEventListenerB : * B接收任务:{"finish":false,"id":1,"taskContext":"任务内容","taskName":"测试任务"}
2020-11-30 18:13:59.921 INFO 19776 --- [ main] com.example.controller.MyEventListenerB : * B此时完成任务
2020-11-30 18:13:59.921 INFO 19776 --- [ main] com.example.controller.PublishEventDemo : 结束发布任务
2020-11-30 18:14:03.913 INFO 19776 --- [ task-1] com.example.controller.MyEventListenerA : * A接收任务:{"finish":true,"id":1,"taskContext":"任务内容","taskName":"测试任务"}
2020-11-30 18:14:03.913 INFO 19776 --- [ task-1] com.example.controller.MyEventListenerA : * A此时完成任务
2020-11-30 18:14:09.958 INFO 19776 --- [ Thread-3] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
事件发送后,会等待事件执行完毕,因此他们是同步的。若想异步执行事件,可以把@Async加到监听方法上;
2. 使用ApplicationContext发布事件
与上例不同之处
使用ApplicationContext发布事件,ApplicationContext实现了ApplicationEventPublisher接口;
使用ApplicationContextEvent 定义事件,ApplicationContextEvent 继承了ApplicationEvent类;
demo代码:
package com.example.controller;
import ch.qos.logback.classic.Logger;
import com.example.SpringbootRedisApplication;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ApplicationContextEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.RestController;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SpringbootRedisApplication.class)
@RestController
@Slf4j
public class PublishEventDemo2 {
/**
* 使用ApplicationContext发布事件
*/
@Autowired
ApplicationContext applicationContext;
@Test
public void send() {
MyEvent2 myEvent2 = new MyEvent2(applicationContext);
myEvent2.setData("数据");
log.info("开始发送事件");
applicationContext.publishEvent(myEvent2);
log.info("结束发送事件");
}
}
/**
* * 类
*/
@Slf4j
@Component
class MyEventListener2 implements ApplicationListener<MyEvent2> {
@Override
public void onApplicationEvent(MyEvent2 event) {
log.info(" * MyEventListener2收到={}", event);
}
@EventListener
public void someMethod(MyEvent2 event) {
log.info(" * MyEventListener2@EventListener收到={}", event);
}
}
/**
* * 类
*/
@Slf4j
@Component
class MyEventListenner1 {
@EventListener
public void someMethod(MyEvent2 event) {
log.info(" * MyEventListenner1收到={}", event);
}
}
/**
* 事件类
*
* @param <T>
*/
@ToString
class MyEvent2<T> extends ApplicationContextEvent {
private T data;
public MyEvent2(ApplicationContext source) {
super(source);
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
运行日志:
2020-11-30 18:03:38.638 INFO 15792 --- [ main] c.example.controller.PublishEventDemo2 : Started PublishEventDemo2 in 9.571 seconds (JVM running for 12.677)
2020-11-30 18:03:39.355 INFO 15792 --- [ main] c.example.controller.PublishEventDemo2 : 开始发送事件
2020-11-30 18:03:39.358 INFO 15792 --- [ main] com.example.controller.MyEventListener2 : * MyEventListener2@EventListener收到=MyEvent2(data=数据)
2020-11-30 18:03:39.359 INFO 15792 --- [ main] c.example.controller.MyEventListenner1 : * MyEventListenner1收到=MyEvent2(data=数据)
2020-11-30 18:03:39.359 INFO 15792 --- [ main] com.example.controller.MyEventListener2 : * MyEventListener2收到=MyEvent2(data=数据)
2020-11-30 18:03:39.359 INFO 15792 --- [ main] c.example.controller.PublishEventDemo2 : 结束发送事件
2020-11-30 18:03:39.435 INFO 15792 --- [ Thread-3] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
事件发送后,会等待事件执行完毕,因此他们是同步的。若想异步执行事件,可以把@Async加到监听方法上;
来源:https://blog.csdn.net/A434534658/article/details/110392200


猜你喜欢
- 一、 DataTable转换到List<T>/// <summary> /// TableT
- java.lang.StackOverflowError出现的原因严重: Exception initializing page conte
- 前言在 Java 中通常对一些方法进行一些注解操作,但是很多注解在 Java 代码上没有问题,如果切换到 Kotlin 上时,如果继续使用这
- 工作需求,要播放一张gif图片,又不想转成视频播放,就开始研究怎样解析gif,在网上也看了不少教程,最后根据自己需求写了个脚本。首先,Uni
- 1.Fork/Join框架简介Fork/Join 它可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果,并
- 本文实例为大家分享了Android实现象棋游戏的具体代码,供大家参考,具体内容如下主要是实现两人对战象棋,没有实现人机对战,主要不会判断下一
- 首先是main.xml文件代码如下:<LinearLayout xmlns:android="http://schemas.
- 使用线程池的好处1、降低资源消耗可以重复利用已创建的线程降低线程创建和销毁造成的消耗。2、提高响应速度当任务到达时,任务可以不需要等到线程创
- 本文实例讲述了Android编程使用Service实现Notification定时发送功能。分享给大家供大家参考,具体如下:/** * 通过
- 一、问题Spring2.1.5集成activiti7.1.24时访问要输入用户名和密码。 @Autowired private
- 1.Java 9以前堆栈遍历到目前为止,官方解决方案是获取当前线程并调用其getStackTrace()方法:StackTraceEleme
- 该说不唠,直接上代码。可直接复制使用package com.yuezhi.util;import java.math.BigDecimal;
- 一、广播机制概述通常情况下在学校的每个教室都会装有一个喇叭,这些喇叭是接入到学校广播室的。如果有重要通知,会发送一条广播来告知全校师生。为了
- 本文实例讲述了Android使用Eclipse 打开时“发现了以元素'd:skin'”开头的无效内容。此处不应含有子元素的解
- 插入排序插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。插入
- Java关于Map的四种取值方式map的主要作用是什么?可以通过创建一个map的实现类 来存放 数据 值 和值的描述 也可以通过描述去取得数
- java 避免出现NullPointerException(空指针)的方法总结Java应用中抛出的空指针异常是解决空指针的最好方式,也是写出
- @Value注解读取yml中的map配置网上查了好多资料,都是.properties文件中读取,而且又是几个人抄来抄去,找了半天功夫不负有心
- class文件中的特殊字符串首先说明一下, 所谓的特殊字符串出现在class文件中的常量池中,本着循序渐进和减少跨度的原则, 首先把clas
- android大家都有很多需要用户上传头像的需求,有的是选方形,有的是圆角矩形,有的是圆形。首先我们要做一个处理图片的自定义控件,把传入的图