Spring Boot学习笔记:ApplicationEvent和ApplicationEventListener事件监听
采用事件监听的好处
以用户注册的业务逻辑为例,用户在填写完信息表单后,提交信息到后台,后台对用户信息进行处理,然后给用户返回处理结果的信息。

如上图所示,用户在注册时,后台需要处理一些系列流程,实际业务逻辑可能更加复杂。这样写很直观,但是不利于后期新业务逻辑的添加。
如果采用事件监听的模式,上面的流程就可以变成如下:

用户在注册的过程中,发送一个信号给监听对象,而这个信号就是用户正在注册的事件,监听对象在收到信号时,就会在后台处理这些流程,如果采用异步事件处理的方式,用户的主干逻辑可以快速完成,而且如果后期需要在注册流程中加入新的逻辑也只需要在监听对象处理事件的过程中加入新的逻辑。
实际代码演示
首先是项目结构,如下
- controller 处理用户注册请求
- service 处理用户注册逻辑
- event 存放事件对象
- listener 在event的子目录下 监听并调用逻辑处理事件
- config 存放配置文件
原本还应该有entity和repository层,为简化逻辑,暂时不加

非异步事件处理
编写用户注册事件类,放在event包内,这个类可以根据需求添加一些属性,而这些属性就是代表发生这件事的基本信息。可以通俗的理解,要知道一件事,前提肯定要知道是什么事情。我在这里添加了属性username,表示用户名。
public class UserRegisterEvent extends ApplicationEvent {
private String userName;
public UserRegisterEvent(Object source, String userName) {
super(source);
this.userName = userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserName() {
return userName;
}
}
编写listener事件监听,用来处理这些事情。当用户注册时,先保存用户注册的信息到数据库,然后给用户发送邮件(本次简化了逻辑,只在控制台打印了信息)。需要在事件处理器上面加上注解@EventListener,一旦事件UserRegisterEvent被发布,监听器就会监听这个事件,然后处理,处理的方式是:保存用户信息,给用户发送邮件。(为了模拟发送邮件这个较为复杂而且耗时的事情,我让线程暂停了5秒,然后继续执行)
@Component
public class UserListener { @EventListener
public void handleUserRegisterEvent(UserRegisterEvent userRegisterEvent) { // save user information
System.out.println(Calendar.getInstance().getTime() + " " + "user information " + userRegisterEvent.getUserName()); // send email to user
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Calendar.getInstance().getTime() + " " + "send Email to " + userRegisterEvent.getUserName());
} }
编写controller层,模拟用户注册,当用户访问localhost:8080/register/{username}时,就算用户注册,注册成功后给用户返回一个hello
@RestController
public class UserController { @Autowired
private UserService userService; @GetMapping("/register/{username}")
public ResponseEntity<String> register(@PathVariable(name = "username") String username){
return ResponseEntity.ok(userService.register(username));
}
}
编写service层,在UserService返回用户注册成功的信息时,先要发布事件,需用ApplicationEventPulisher接口中的pulishEvent( )方法,这个方法的参数就是我们前面创建的UserRegisterEvent的一个对象(注意往对象中存放一些用户基本信息,便于处理器通过这些信息处理事件),当程序运行到这里时就相当于发出一个信号:某某用户正在注册!
@Service
public class UserService { @Autowired
ApplicationEventPublisher publisher; public String register(String username) {
publisher.publishEvent(new UserRegisterEvent(this, username));
return "hello " + username + " " + Calendar.getInstance().getTime();
} }
启动应用程序,访问localhost:8080/register/tom,等待一段时间后就可以看到返回的注册成功信息hello tom,控制台也可以看到用户注册的时一些流程也执行了。

这样就完成了事件监听处理业务逻辑。
异步事件的处理
通过上面的例子已经完成了事件监听,但是也存在一些问题,例如假如发送邮件比较耗时,例如上面的例子,花了5秒钟,那么用户就需要等待五秒,才可以接受到返回的信息。看上面的例子,后台保存用户信息时间是18时38分47秒,邮件发送完毕是18时38分52秒,等到用户接到到信息时已经是18时38分52秒了,这样用户体验显然很差。采用异步事件的方式,新建一个线程,将处理事件放到新的线程中,这样就可以显著提高用户的体验。
要变成异步事件处理,在上面的例子上稍做修改即可:
在UserListener中,在需要做异步处理的方法上加上注解@Async

然后在项目启动类上加上注解@EnableAsync

只要加上这两个注解就可以了。
再次启动项目,访问localhost:8080/register/john,结果如下

可以看到用户很快就获得了响应。
补充:如果想自己控制线程,可以在config文件夹下加入配置类,代码如下
public class ListenerAsyncConfiguration implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
//使用Spring内置线程池任务对象
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
//设置线程池参数
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(10);
taskExecutor.setQueueCapacity(25);
taskExecutor.initialize();
return taskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
总结:采用事件监听的方式可以很轻松实现业务逻辑的解耦,方便后期业务逻辑的扩展。
Spring Boot学习笔记:ApplicationEvent和ApplicationEventListener事件监听的更多相关文章
- Cocos2dx 3.1.1 学习笔记整理(4):事件监听与Action的初步使用
项目忙,趁着刚才有点空,看了下触摸事件在新版本中怎么实现,遇到问题都是去:cocos2d-x-3.1.1\tests\cpp-tests\Classes下面找的,里面都是一些小例子. 首先新的CCNo ...
- Spring Boot学习笔记2——基本使用之最佳实践[z]
前言 在上一篇文章Spring Boot 学习笔记1——初体验之3分钟启动你的Web应用已经对Spring Boot的基本体系与基本使用进行了学习,本文主要目的是更加进一步的来说明对于Spring B ...
- Spring Boot 学习笔记(六) 整合 RESTful 参数传递
Spring Boot 学习笔记 源码地址 Spring Boot 学习笔记(一) hello world Spring Boot 学习笔记(二) 整合 log4j2 Spring Boot 学习笔记 ...
- Spring Boot 学习笔记一(SpringBoot启动过程)
SpringBoot启动 Spring Boot通常有一个名为*Application的入口类,在入口类里有一个main方法,这个main方法其实就是一个标准的java应用的入口方法. 在main方法 ...
- Halo 开源项目学习(六):事件监听机制
基本介绍 Halo 项目中,当用户或博主执行某些操作时,服务器会发布相应的事件,例如博主登录管理员后台时发布 "日志记录" 事件,用户浏览文章时发布 "访问文章" ...
- Spring Boot 学习笔记1——初体验之3分钟启动你的Web应用[z]
前言 早在去年就简单的使用了一下Spring Boot,当时就被其便捷的功能所震惊.但是那是也没有深入的研究,随着其在业界被应用的越来越广泛,因此决定好好地深入学习一下,将自己的学习心得在此记录,本文 ...
- Spring Boot 学习笔记1---初体验之3分钟启动你的Web应用
前言 早在去年就简单的使用了一下Spring Boot,当时就被其便捷的功能所震惊.但是那是也没有深入的研究,随着其在业界被应用的越来越广泛,因此决定好好地深入学习一下,将自己的学习心得在此记录,本文 ...
- Spring Boot 学习笔记--整合Thymeleaf
1.新建Spring Boot项目 添加spring-boot-starter-thymeleaf依赖 <dependency> <groupId>org.springfram ...
- Spring Boot 学习笔记
参考资料 http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/ Spring Boot简介 Spring Boot使 ...
随机推荐
- linux安装zookeeper及使用
一.安装条件 想要安装zookeeper,必须先在linux中安装好jdk.安装步骤见: https://www.cnblogs.com/expiator/p/9987351.html 二.下载并解压 ...
- Hadoop特点
一:HDFS 1.HDFS上传数据,会将文件切分成指定大小的数据块,并以多副本的数据块存储在机器上. 2. part0是指 副本有2个而且1,2有两个副本 二.YARN 1.负责整个集群的管理和调度 ...
- JAVA去重
JAVA中去掉空格 1. String.trim() trim()是去掉首尾空格 2.str.replace(" ", ""); 去掉所有空格,包括首尾.中间 ...
- Reportviewer中的函数使用——打印当前日期并格式化
如2017-10-23 12:20:20 通过DateTime.Now.ToString("yyMMddHHmmss")变为 20171023122020字符串
- chrome谷歌浏览器常用快捷键搜集整理
搜集了下面比较实用的快捷键,部分不好操作的组合键就不写了:Ctrl+N:打开新窗口. Ctrl+T:打开新标签页.Ctrl+W:关闭当前标签Alt+F4:关闭chrome浏览器Ctrl+Tab:切换到 ...
- socket、fsockopen、curl、stream 区别
socket 水泥.沙子,底层的东西fsockopen 水泥预制件,可以用来搭房子curl 毛坯房,自己装修一下就能住了 水泥.沙子不但可以修房子,还能修路.修桥.大型雕塑.socket也是,不但可以 ...
- openal支持的通道数和声道数
alext.h: #define AL_FORMAT_QUAD8 0x1204 101 #define AL_FORMAT_QUAD16 0x1205 102 #define AL_FORMAT_Q ...
- JD_M案例知识点(移动端)
# JD_M案例知识点 基础布局+顶部通栏+顶部轮播图+导航栏 知识点 base.css ::before,::after 伪元素 统一设置文字 sans-serif 移动端 的默认字体 font-f ...
- gearman管理工具GearmanManager的安装与使用
一.gearman自带了一个gearadmin工具 查看帮助信息 > gearadmin --help 查看状态 > gearadmin --status 查看worker信息 > ...
- 基于RBAC权限验证, 中间价middleware实现, views 登录视图代码
废话不多说 上代码: 基础实现: rom django.shortcuts import HttpResponse, redirect, render from django.http import ...