在SpringBoot使用ApplicationEvent&ApplicationListener完成业务解耦
前言:
项目中往往各个业务逻辑之间耦合性较强,因为我们在service都是直接引用的关联service或者jpa来作为协作处理逻辑,然而这种方式在后期更新、维护性难度都是大大提高了。通过使用事件通知、事件监听形式来处理逻辑时耦合性则是可以降到最小。
spring中事件监听实现
ApplicationEvent、ApplicationListener是Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式,设计初衷也是为了系统业务逻辑之间的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。
下面我们通过使用ApplicationEvent和ApplicationListener来完成简单的用户注册,以及注册成功后发送邮件的例子。
1、开始我们的示例之前,我们先定义一个User对象
public class User implements java.io.Serializable{
private static final long serialVersionUID = 110406535439289650L;
private String username;
private String password;
//省略get/set方法
}
2、创建UserRegisterEvent
定义一个用户注册事件,监听都是围绕着事件来挂起的。
public class UserRegisterEvent extends ApplicationEvent{
private static final long serialVersionUID = -2493647928101170759L;
//注册用户事件
private User user;
//重写构造函数
public UserRegisterEvent(Object source,User user) {
super(source);
this.user = user;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
我们自定义事件UserRegisterEvent继承了ApplicationEvent,继承后必须重载构造函数,构造函数的参数可以任意指定,其中source参数指的是发生事件的对象,一般我们在发布事件时使用的是this关键字代替本类对象,而user参数是我们自定义的注册用户对象,该对象可以在监听内被获取。
3、创建UserService
UserService类中添加一个registerUser方法,该方法实现注册事件发布功能
@Service
public class UserService {
@Autowired
private ApplicationContext applicationContext;
public void registerUser(User user){
//发布注册事件
applicationContext.publishEvent(new UserRegisterEvent(this, user));
}
}
事件发布是由ApplicationContext对象管控的,我们发布事件前需要注入ApplicationContext对象调用publishEvent方法完成事件发布。
4、创建UserController
创建一个@RestController控制器,对应添加一个注册方法简单实现
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/user/register")
public String registerUser(){
User user = new User();
user.setPassword("12346");
user.setUsername("admin");
//调用注册业务逻辑
userService.registerUser(user);
return "success";
}
}
5、监听UserRegisterEvent事件
在Spring内部中有多种方式实现监听如:@EventListener注解、实现ApplicationListener泛型接口、实现SmartApplicationListener接口等,我们下面来讲解下这三种方式分别如何实现。
6、@EventListener实现
@Component
public class AnnotationRegisterListener {
@EventListener
public void userRegister(UserRegisterEvent registerEvent){
System.out.println("注册的用户信息如下:"+registerEvent.getUser());
}
@EventListener
public void userRegisterEmail(UserRegisterEvent registerEvent){
System.out.println("用户注册成功"+registerEvent.getUser().getUsername()+",发送邮件");
}
}
我们只需要让我们的监听类被Spring所管理即可,在我们用户注册监听实现方法上添加@EventListener注解,该注解会根据方法内配置的事件完成监听。下面我们启动项目来测试下我们事件发布时是否被监听者所感知。
测试事件监听
浏览器访问http://localhost:8080/user/register,调用接口注册用户,输出信息如下:
注册的用户信息如下:User [username=admin, password=12346]
用户注册成功admin,发送邮件
可以看到我们使用@EventListener注解配置的监听已经生效了,当我们在UserService内发布了注册事件时,监听方法自动被调用并且输出内信息到控制台。
7、ApplicationListener实现监听
在实现ApplicationListener接口时需要将监听事件作为泛型传递,监听实现代码
@Component
public class RegisterApplicationListener implements ApplicationListener<UserRegisterEvent>{
@Override
public void onApplicationEvent(UserRegisterEvent event) {
System.out.println("用户注册信息如下:"+event.getUser());
}
}
@Component
public class RegisterEmailApplicationListener implements ApplicationListener<UserRegisterEvent>{
@Override
public void onApplicationEvent(UserRegisterEvent event) {
System.out.println("用户注册成功,发送邮件");
}
}
我们实现接口后需要使用@Component注解来声明该监听需要被Spring注入管理,当有UserRegisterEvent事件发布时监听程序会自动调用onApplicationEvent方法并且将UserRegisterEvent对象作为参数传递。
测试成功,同步骤6测试
8、SmartApplicationListener实现监听
当多个listener监听同一个事件时,监听是无序的,监听到的事件先后顺序完全随机出现的,通过SmartApplicationListener可以实现监听逻辑的有序性。
@Component
public class RegisterSmartApplicationListener implements SmartApplicationListener{
//supportsEventType和supportsSourceType返回为true时,才会执行监听
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("用户注册信息如下:"+((UserRegisterEvent)event).getUser());
}
/**
* 同步情况下的事件监听顺序
* @see org.springframework.core.Ordered#getOrder()
*/
@Override
public int getOrder() {
//值越小,优先级越高,执行越靠前
return 0;
}
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return eventType == UserRegisterEvent.class;
}
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return sourceType == UserService.class;
}
}
@Component
public class RegisterEmainSmartApplicationListener implements SmartApplicationListener{
//supportsEventType和supportsSourceType返回为true时,才会执行监听
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("用户注册成功,发送电子邮件"+((UserRegisterEvent)event).getUser());
}
/**
* 同步情况下的事件监听顺序
* @see org.springframework.core.Ordered#getOrder()
*/
@Override
public int getOrder() {
//值越小,优先级越高,执行越靠前,用户注册成功后才发送邮件
return 1;
}
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return eventType == UserRegisterEvent.class;
}
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return sourceType == UserService.class;
}
}
通过SmartApplicationListener提供的getOrder方法,该方法可以实现监听的有序性,return的数值越小证明优先级越高,执行顺序越靠前。
测试同步骤6的测试
9、使用@Async实现异步监听
@Aysnc其实是Spring内的一个组件,可以完成对类内单个或者多个方法实现异步调用,这样可以大大的节省等待耗时。内部实现机制是线程池任务ThreadPoolTaskExecutor,通过线程池来对配置@Async的方法或者类做出执行动作。
配置线程池,如下:
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public AsyncTaskExecutor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
threadPool.setCorePoolSize(2);//当前线程数
threadPool.setMaxPoolSize(50);// 最大线程数
threadPool.setQueueCapacity(100);//线程池所使用的缓冲队列
threadPool.setWaitForTasksToCompleteOnShutdown(true);//等待任务在关机时完成--表明等待所有线程执行完
threadPool.setThreadNamePrefix("provider-demo-");
threadPool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return threadPool;
}
}
使用@Async实现异步监听,在具体的监听方法onApplicationEvent上面添加Async注解,用法同普通的方法上面加Async注解一致
@Override
@Async
public void onApplicationEvent(ApplicationEvent applicationEvent) {
System.out.println("用户注册成功,发送邮件通知。");
}
注意:如果存在多个监听同一个事件时,并且存在异步与同步同时存在时则不存在执行顺序。
相关推荐
EL&Filter&Listener-授课
主要介绍了Spring ApplicationListener的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
Spring使用ApplicationEvent和ApplicationListener两个核心接口实现了事件监听机制。开发者可以自定义事件类和事件监听器,并通过应用程序上下文的publishEvent方法来发布事件,Spring框架会自动分发事件给所有对该...
主要介绍了Spring ApplicationListener监听器用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
TODO Spring注解驱动开发第39讲——你不知道的ApplicationListener的原理
TODO Spring注解驱动开发第38讲——你知道ApplicationListener的用法吗?
主要介绍了SpringMVC事件监听ApplicationListener实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
1. 发布订阅/观察者模型,实现业务之间的解耦。 2.比如新增用户完成需要发短信、记录日志等,这些逻辑堆在新增方法的最后面实在不太合理,而且不易复用。 3.对解耦代码有很大的帮助,比如多种业务场景做完都要插入...
内容:中介者模式、观察者模式/监听者模式实现,用来消息发送和消息处理的解耦,以单播和多播形式同步或异步的模式发布消息,...能学到:ApplicationContext、ApplicationEvent、ApplicationListener,@EventListener
Java进阶-Filter&Listener&Ajax&Json(十五).zip
1、Filter 什么是过滤器 3、Filter 过滤器它的作用是:拦截请求,过滤响应 1、权限检查 2、日记操作 3、事务管理 1、编写一个类去实现 Filt
此资源与我的博客12_JavaWeb——Filter&Listener中的案例对应,在11_JavaWeb——Cookie&Session案例资源基础上加上了过滤器,实现了对未登录用户的拦截,希望有所帮助。
Filter,Listener和Ajax的详细学习教程
案例
2. 过滤器执行流程 1. 执行过滤器 2. 执行放行后的资源 3. 回来执行过滤器放行代码下边的代码请描述Filter的生命周期 3. 过滤器生命周期方
ApplicationEvent 是 Spring 框架中的一个重要概念,它是...这个接口定义了一个方法:void onApplicationEvent(E event),当某个 ApplicationEvent 被发布时,所有注册监听该事件的 ApplicationListener 将会被调用。
它们可以通过实现ApplicationListener接口或使用@EventListener注解来定义。这些监听器关注特定类型的事件,并在事件发生时执行定义的逻辑。Spring的事件机制允许一个事件被多个监听器监听,增加了灵活性和可扩展性...
Spring的ApplicationEvent事件和监听器的测试工程,演示了如何使用Spring中的事件和监听器内容。完整的maven工程,能够运行。
11.1 Web应用的事件模型 11.2 Web应用的过滤器 11.3 小 结 11.1.1 事件与监听器接口 11.1.2 监听环境事件 11.1.3 监听请求事件 11.1.4 监听会话事件 11.1.5 事件监听器的注册
关于SWING基本功能,按键以及事件触发器使用源代码。对于初学JAVA的有较好帮助。