采用事件监听的好处

以用户注册的业务逻辑为例,用户在填写完信息表单后,提交信息到后台,后台对用户信息进行处理,然后给用户返回处理结果的信息。

如上图所示,用户在注册时,后台需要处理一些系列流程,实际业务逻辑可能更加复杂。这样写很直观,但是不利于后期新业务逻辑的添加。

如果采用事件监听的模式,上面的流程就可以变成如下:

用户在注册的过程中,发送一个信号给监听对象,而这个信号就是用户正在注册的事件,监听对象在收到信号时,就会在后台处理这些流程,如果采用异步事件处理的方式,用户的主干逻辑可以快速完成,而且如果后期需要在注册流程中加入新的逻辑也只需要在监听对象处理事件的过程中加入新的逻辑。

实际代码演示

首先是项目结构,如下

  • 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事件监听的更多相关文章

  1. Cocos2dx 3.1.1 学习笔记整理(4):事件监听与Action的初步使用

    项目忙,趁着刚才有点空,看了下触摸事件在新版本中怎么实现,遇到问题都是去:cocos2d-x-3.1.1\tests\cpp-tests\Classes下面找的,里面都是一些小例子. 首先新的CCNo ...

  2. Spring Boot学习笔记2——基本使用之最佳实践[z]

    前言 在上一篇文章Spring Boot 学习笔记1——初体验之3分钟启动你的Web应用已经对Spring Boot的基本体系与基本使用进行了学习,本文主要目的是更加进一步的来说明对于Spring B ...

  3. Spring Boot 学习笔记(六) 整合 RESTful 参数传递

    Spring Boot 学习笔记 源码地址 Spring Boot 学习笔记(一) hello world Spring Boot 学习笔记(二) 整合 log4j2 Spring Boot 学习笔记 ...

  4. Spring Boot 学习笔记一(SpringBoot启动过程)

    SpringBoot启动 Spring Boot通常有一个名为*Application的入口类,在入口类里有一个main方法,这个main方法其实就是一个标准的java应用的入口方法. 在main方法 ...

  5. Halo 开源项目学习(六):事件监听机制

    基本介绍 Halo 项目中,当用户或博主执行某些操作时,服务器会发布相应的事件,例如博主登录管理员后台时发布 "日志记录" 事件,用户浏览文章时发布 "访问文章" ...

  6. Spring Boot 学习笔记1——初体验之3分钟启动你的Web应用[z]

    前言 早在去年就简单的使用了一下Spring Boot,当时就被其便捷的功能所震惊.但是那是也没有深入的研究,随着其在业界被应用的越来越广泛,因此决定好好地深入学习一下,将自己的学习心得在此记录,本文 ...

  7. Spring Boot 学习笔记1---初体验之3分钟启动你的Web应用

    前言 早在去年就简单的使用了一下Spring Boot,当时就被其便捷的功能所震惊.但是那是也没有深入的研究,随着其在业界被应用的越来越广泛,因此决定好好地深入学习一下,将自己的学习心得在此记录,本文 ...

  8. Spring Boot 学习笔记--整合Thymeleaf

    1.新建Spring Boot项目 添加spring-boot-starter-thymeleaf依赖 <dependency> <groupId>org.springfram ...

  9. Spring Boot 学习笔记

    参考资料 http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/ Spring Boot简介 Spring Boot使 ...

随机推荐

  1. Mysql 用户 创建与删除(基础1)

    Mysql是最流行的关系型数据库管理系统之一,由瑞典MySQL AB公司开发,目前属于Oracle公司. MySQL是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个 ...

  2. 用BlazeMeter录制JMeter(三十五)测试脚本(转载)

    转载自 http://www.cnblogs.com/yangxia-test 工具: 1,JMeter 2,Chrome 3,BlazeMeter 4,SwitchyOmega(如果需要代理) 步骤 ...

  3. Ambertools15安装(详细)

    这篇博文专门讲述 Ambertools15的安装方法,尽管Ambertools16版本已经正是发行了,但两者在安装方式上没有任何区别.比较偏爱Ambertools15的原因主要还是在容量方面(230M ...

  4. js两个数组对象通过相同元素匹配筛选

    let a = [ { name: 'joy', year: '24' }, { name: 'eve', year: '25' } ] let b = [ { name: 'joy', city: ...

  5. for 与 for in

    在JavaScript中提供了两种方式迭代对象: (1)for 循环: (2)for..in循环: 使用for循环进行迭代数组对象,想必大家都已经司空见惯了.但是,使用for.. in循环时,大家可要 ...

  6. Android 集成高德地图

    先上一张图片看看实现的效果啦!!! 首先登陆高德的开发者平台进行创建自己的应用程序,填写对应的包名,填写sHA1值(这个我这博客中写了获取的代码,可以直接复制粘贴),说了这么多其实都是废话,来我们看重 ...

  7. 牛客练习赛15A-吉姆的运算式(Python正则表达式瞎搞)

    传送门 题意:出现的数字,取最后一个数字即可. Python正则表达式提取数字 代码: import re str = input() a = re.findall(r'\-*\d+(?:\.\d+) ...

  8. 解决vue-router嵌套路由(子路由)在history模式下刷新无法渲染页面的问题

    一. 异常描述: 本来使用的是vue-router的hash模式,但是hash模式下url需要带“#”符号,不仅看起来不舒服,而且有些场景下是会破坏路由中的"#"(微信分享页面就会 ...

  9. eclipse Mars4.5.2安装fatjar

    试了在eclipse下添加plugins的方法,但是并没有生效 最后看了一篇博客@参考博客 原文转载: 首先声明,eclipse luna 和mars 楼主亲测可用. .安装Eclipse2.0版本的 ...

  10. 8.14 git??sourceTree??

    目前这个项目是四个前端在做,我用的版本控制工具是sourceTree,有两个人用的是命令行,厉害.(刚哥说,肯定要会命令行的,(⊙o⊙)好,我学!!) 上周五提交代码时,文件冲突了,而且我给1.3版本 ...