logo头像
Snippet 博客主题

springboot事件发布监听

本文于 2123 天之前发表,文中内容可能已经过时。

近期在项目中遇到需要事件发布和监听的场景:
以前存在一段比较复杂的代码流程,比如:创建的数据,在通过审批之后需要同步到其他表里边,现在需要在同步到其他表的同时需要计算某一批数据并推送给另外一个接口,那么我们该怎样发布我们的事件,并成功监听到,并且执行相关的逻辑呢?

1. 定义事件

我们定义一个事件,包括两个参数,此事件必须继承ApplicationEvent才可保证在publish时可以正常监听到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class CalCourierAndSalesDeptDistance extends ApplicationEvent {
/**
* Create a new ApplicationEvent.
*
* @param source the object on which the event initially occurred (never {@code null})
*/
private String type;

private String deptCode;

public CalCourierAndSalesDeptDistance(Object source, String type, String deptCode) {
super(source);
this.type = type;
this.deptCode = deptCode;
}

public boolean isNotNull(){
return StringUtils.isNotEmpty(this.getType()) && StringUtils.isNotEmpty(this.getDeptCode());
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

public String getDeptCode() {
return deptCode;
}

public void setDeptCode(String deptCode) {
this.deptCode = deptCode;
}
}

2.如何发布事件?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component
public class DistanceCalPublish implements ApplicationEventPublisherAware {

private ApplicationEventPublisher applicationEventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}

// 这个方法用于接收发送给监听的数据,并封装成事件对象,并发送给监听
public void publish(String type, String deptCode){
CalCourierAndSalesDeptDistance calCourierAndSalesDeptDistance = new CalCourierAndSalesDeptDistance(this, type, deptCode);
this.applicationEventPublisher.publishEvent(calCourierAndSalesDeptDistance);
}
}

本类继承ApplicationEventPublisherAware是用于发布事件使用,通过@Component是为了在SpringBoot启动的时候可以自动扫描到本类使用Bean来管理。
代码里边applicationEventPublisher.publishEvent这个方法可以接收一个Object的类型数据(将定义的事件放到此处),所以可以将需要发送给监听事件的数据通过这个参数传输。

3.如何监听?

1
2
3
4
5
6
7
8
9
10
11
@Component
@EnableAsync(proxyTargetClass=true)
public class CalRegionDistanceHandler {

@Async("RegionDistanceHandlerExecutor")
// 这里可以保证监听到创建的事件
@EventListener(classes = CalCourierAndSalesDeptDistance.class)
public void handler(CalCourierAndSalesDeptDistance calCourierAndSalesDeptDistance) {
// 拿到数据,执行接下来的处理
}
}
  1. @Component:上述代码中的作用和发布时相同。
  2. @EnableAsync:打开异步执行,因为我们的事件的执行不需要影响原流程,所以异步即可。
  3. 方法handler:处理事件的方法,baseId是从发布事件的地方拿到的。
  4. @EventListener:可开启对事件的监听。
  5. @Async:异步处理的标志,括号中的参数为定义的线程池。

线程池的定义如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
public class ConmmonConfig {

@Value("${common.threadPoolsSize:20}")
private int threadPoolsSize;

@Bean("RegionDistanceHandlerExecutor")
public ThreadPoolTaskExecutor msgHandlerExecutor(){
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(threadPoolsSize);
taskExecutor.setMaxPoolSize(threadPoolsSize);
return taskExecutor;
}
}

3.如何使用?

  1. 在使用的类中先注入该publish
1
2
@Autowired
GridSplitPublish publish;
  1. 在合适的实际发布事件
1
2
publish.publish(xxxx);
// 其中xxx为需要发送给事件监听的参数

4.事件监听到此为止

图片