SpringBoot 有序事件监听器
实现 SmartApplicationListener
重写supportsEventType、supportsSourceType来区分是否是我们监听的事件,只有两个方法同时返回true时才会执行,getOrder这个方法可以解决执行监听的顺序问题,return的数值越小证明优先级越高,执行顺序越靠前。
用户注册发送邮件
首先创建一个事件,监听都是围绕着事件
import com.base.client.model.vo.UserVO;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;
/**
* 用户创建事件
*
* @author arjun
* @date 2020/12/09
*/
@Getter
public class UserRegisterEvent extends ApplicationEvent {
/**
* 发送的内容
*/
private UserVO content;
/**
* 重写构造器
*
* @param source 发送事件的对象
* @param content 发送的内容
*/
public UserRegisterEvent(Object source, UserVO content) {
super(source);
this.content = content;
}
}
创建
UserService
只用于实现注册事件发布功能(当然业务逻辑也是可以写,这里只为测试)
这里注入
ApplicationEventPublisher
接口
import com.base.client.model.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
/**
* @author arjun
* @date 2020/12/09
*/
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void register(UserVO vo) {
System.out.println("----------------发布注册事件----------------------");
// 发布 UserRegisterEvent 事件
eventPublisher.publishEvent(new UserRegisterEvent(this, vo));
}
}
ApplicationEvent
监听所有事件发布,
SmartApplicationListener
接口添加了两个方法
supportsEventType
、
supportsSourceType
来区分是否是我们监听的事件,只有两个方法同时返回true时才会执行
onApplicationEvent
,
getOrder
这个方法可以解决执行监听的顺序问题,return的数值越小证明优先级越高,执行顺序越靠前。
import com.base.client.model.vo.UserVO;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;
/**
* @author arjun
* @date 2020/12/09
*/
@Component
public class UserRegisterListener implements SmartApplicationListener {
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
return aClass == UserRegisterEvent.class;
}
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return sourceType == UserService.class;
}
@Override
public int getOrder() {
return 2;
}
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
System.out.println("----------------监听用户注册----------------------");
UserRegisterEvent registerEvent = (UserRegisterEvent) applicationEvent;
UserVO vo = registerEvent.getContent();
System.out.println("----------------用户正在注册----------------------");
vo.setEmail("[email protected]");
vo.setUserName("name");
vo.setPassword("666");
System.out.println("用户注册:邮箱:" + vo.getEmail() + ", 用户名:" + vo.getUserName() + ", 密码:" + vo.getPassword());
System.out.println("----------------用户注册完成----------------------");
}
}
这里return为“2”,优先级将靠后
import com.base.client.model.vo.UserVO;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;
/**
* 监听系统用户创建并发送邮件通知 有序监听
*
* @author arjun
* @date 2020/12/09
*/
@Component
public class UserRegisterSentMailListener implements SmartApplicationListener {
/**
* 接收到的监听事件类型
*/
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
return aClass == UserRegisterEvent.class;
}
/**
* 发布该事件的Source类型
*/
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return sourceType == UserService.class;
}
/**
* 同步下监听执行顺序 -- 数值越低优先级越高
*/
@Override
public int getOrder() {
return 1;
}
/**
* supportsEventType & supportsSourceType 两个方法返回true 时调用该方法执行业务逻辑
*
* @param applicationEvent 具体的监听事件
*/
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
System.out.println("----------------监听发送邮件----------------");
// 转换事件类型
UserRegisterEvent registerEvent = (UserRegisterEvent) applicationEvent;
UserVO vo = registerEvent.getContent();
System.out.println("----------------发送邮件----------------");
System.out.println("发送给:" + vo.getEmail() + ", 用户名:" + vo.getUserName() + ", 密码:" + vo.getPassword());
}
}
这里return为“1”,优先级将靠前
运行结果如下
----------------发布注册事件----------------------
----------------监听发送邮件----------------
----------------发送邮件----------------
发送给:null, 用户名:null, 密码:null
----------------监听用户注册----------------------
----------------用户正在注册----------------------
用户注册:邮箱:[email protected], 用户名:name, 密码:666
----------------用户注册完成----------------------
更改
UserRegisterListener
return为“0”,优先级提高
再次运行结果如下:
----------------发布注册事件----------------------
----------------监听用户注册----------------------
----------------用户正在注册----------------------
用户注册:邮箱:[email protected], 用户名:name, 密码:666
----------------用户注册完成----------------------
----------------监听发送邮件----------------
----------------发送邮件----------------
发送给:[email protected], 用户名:name, 密码:666
这次看到的输出结果的顺序就正确了,先保存信息然后再发送邮件通知。
使用@Async异步监听
在Spring中,基于
@Async
标注的方法,称之为异步方法,内部实现机制是线程池任务
ThreadPoolTaskExecutor
,通过线程池来对配置
@Async
的方法或者类做出执行动作。
任务线程池配置
创建一个
SpringAsyncConfig
,并且使用
@EnableAsync
注解开启异步处理:
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
/**
* @author arjun
* @date 2020/12/09
*/
@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {
/**
* 获取异步线程池执行对象
*/
@Override
public Executor getAsyncExecutor() {
// 使用Spring内置线程池任务对象
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置线程池参数
executor.initialize();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
onApplicationEvent
方法上加上
@Async
实现方法异步调用,方法里添加线程阻塞3秒
@Override
@Async
public void onApplicationEvent(ApplicationEvent applicationEvent) {
System.out.println("----------------监听发送邮件----------------");
try {
Thread.sleep(3000);
System.out.println("睡上3秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
// 转换事件类型
UserRegisterEvent registerEvent = (UserRegisterEvent) applicationEvent;
UserVO vo = registerEvent.getContent();
System.out.println("----------------发送邮件----------------");
System.out.println("发送给:" + vo.getEmail() + ", 用户名:" + vo.getUserName() + ", 密码:" + vo.getPassword());
}
}
如果存在多个监听同一个事件,并且同时存在与
同步
两种执行方式,则不存在执行顺序
异步
----------------发布注册事件----------------------
----------------监听用户注册----------------------
----------------用户正在注册----------------------
用户注册:邮箱:[email protected], 用户名:name, 密码:666
----------------用户注册完成----------------------
----------------监听发送邮件----------------
睡上3秒
----------------发送邮件----------------
发送给:[email protected], 用户名:name, 密码:666
同步与异步分别存在,优先级失效