Spring 事件监听
Spring 的事件监听在开发中能为我们做那些事情?
# 背景
大家在做项目的时候,往往会遇到一些不是主流程的功能,但是需要在主流程中触发的功能,比如在保险领域的签单流程中需要给用户发送短信或者邮件的功能。
# 分析
我们都知道这些非主流程中功能,最好不要让主线程去执行,这个时候我们能想到的就是异步线程去执行,我们可以单独搞个线程池,然后异步处理这些任务。
但是总是感觉不太优雅。这时我们可以结合Spring
的事件机制加上异步线程去实现这些功能。
# 实现
我们假定现在你有一个后台管理系统,涉及到登陆和注册两个场景,在注册和登录成功后给用户发送短信邮件提醒或者其他的功能。
# 创建工程
我们为了测试方便就直接创建一个简单的Spring Boot
的工程就可以了。创建的时候引入如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2
3
4
5
6
7
8
9
# 创建事件接口
为了定义统一事件行为,我们定义一个事件接口,代码如下:
public interface Event {
/**
* 发送短信
*/
void sendMsg();
/**
* 发送邮件
*/
void sendMail();
/**
* 其他行为
*/
void other();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 创建登录事件
创建一个登陆事件类,并且实现事件接口。代码如下:
@Data
@Slf4j
public class LoginEvent implements Event {
/**
* 登录的姓名
*/
private String name;
public LoginEvent(String name) {
this.name = name;
}
@Override
public void sendMsg() {
log.info("登录短信内容为:你好:{},欢迎登录该系统",name);
}
@Override
public void sendMail() {
log.info("登录邮件内容为:你好:{},欢迎登录该系统",name);
}
@Override
public void other() {
log.info("登录其他内容为:你好:{},欢迎登录该系统",name);
}
}
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
说明:为什么我们要创建一个接口呢?其实是为了使用策略模式,最大程度的复用事件监听主要代码。
# 创建注册事件
创建一个登陆事件类,并且实现事件接口。代码如下:
@Data
@Slf4j
public class RegisterEvent implements Event {
/**
* 注册人的姓名
*/
private String name;
public RegisterEvent(String name) {
this.name = name;
}
@Override
public void sendMsg() {
log.info("注册短信内容为:你好:{},欢迎注册该系统",name);
}
@Override
public void sendMail() {
log.info("注册邮件内容为:你好:{},欢迎注册该系统",name);
}
@Override
public void other() {
log.info("注册其他内容为:你好:{},欢迎注册该系统",name);
}
}
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
# 创建事件监听
大家注意,事件监听代码的入参是事件监听的接口,这就是为什么要创建一个接口的原因。
注解解释:
@EventListener
-代表是一个监听器@Async
-这个方法需要异步执行
@Component
@Slf4j
public class EventsListener {
/**
* 事件监听
* @param event
*/
@Async
@EventListener
public void handelListener(Event event){
event.sendMsg();
event.sendMail();
event.other();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 测试
我们创建测试类,并且用postman
进行测试
# 创建测试类
我们创建一个控制器来测试登陆和注册的功能。代码如下:
@RestController
public class EventController {
@Resource
LoginService loginService;
@Resource
private ApplicationEventPublisher applicationContext;
@GetMapping("/login")
private String testLoginEvent(){
//登陆的逻辑
loginService.login("张三");
//登陆完成后发布登陆后的事件
applicationContext.publishEvent(new LoginEvent("张三"));
return "success";
}
@GetMapping("/register")
private String testRegisterEvent(){
applicationContext.publishEvent(new RegisterEvent("张三"));
return "success";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 测试
我们Sping Boot
项目,并且进行测试,来看一下效果。
使用postman
请求我们的login方法,我们观察一下日志。请求地址localhost:8111/login
,日志如下:
2023-07-16 17:25:16.774 INFO 7070 --- [nio-8111-exec-1] o.t.s.e.service.impl.LoginServiceImpl : 欢迎:张三,登陆系统。
2023-07-16 17:25:16.795 INFO 7070 --- [ task-1] o.t.s.eventlistener.event.LoginEvent : 登录短信内容为:你好:张三,欢迎登录该系统
2023-07-16 17:25:16.795 INFO 7070 --- [ task-1] o.t.s.eventlistener.event.LoginEvent : 登录邮件内容为:你好:张三,欢迎登录该系统
2023-07-16 17:25:16.795 INFO 7070 --- [ task-1] o.t.s.eventlistener.event.LoginEvent : 登录其他内容为:你好:张三,欢迎登录该系统
2
3
4
可以看到,我们的请求的线程是
[nio-8111-exec-1]
,事件监听的执行是异步线程[task-1]
,这样就实现了我们文章开头所说的功能。
# 说明
大家在使用Spring Boot
的过程中使用到@Async
注解时记得开启该注解的使用。代码如下:
@SpringBootApplication
@EnableAsync
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
2
3
4
5
6
7
8
9
# 小结
本篇文章,我们简单的在实现层面整理了使用Spring
的事件监听机制实现异步功能,后续有机会带着大家分析一下这部分源码,详细代码,大家可以直接进行下载使用源码地址,
希望对大家有所帮助。