ApplicationEvent
以及Listener
是Spring
为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式,设计初衷也是为了系统业务逻辑之间的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。
创建事件监听
我们自定义事件UserRegisterEvent继承了ApplicationEvent,继承后必须重载构造函数,构造函数的参数可以任意指定,其中source
参数指的是发生事件的对象,一般我们在发布事件时使用的是this关键字代替本类对象,而user参数是我们自定义的注册用户对象,该对象可以在监听内被获取。
public class UserRegisterEvent extends ApplicationEvent
{
//注册用户对象
private UserBean user;
/**
* 重写构造函数
* @param source 发生事件的对象
* @param user 注册用户对象
*/
public UserRegisterEvent(Object source,UserBean user) {
super(source);
this.user = user;
}
// 省略Get方法
}
发布时间
在实际的Service中,完成事件的发布
声明上下文
@Autowired
ApplicationContext applicationContext;
发布事件
//发布UserRegisterEvent事件
applicationContext.publishEvent(new UserRegisterEvent(this,user));
监听事件方法一
在我们用户注册监听实现方法上添加@EventListener注解,该注解会根据方法内配置的事件完成监听。
@Component
public class AnnotationRegisterListener {
/**
* 注册监听实现方法
* @param userRegisterEvent 用户注册事件
*/
@EventListener
public void register(UserRegisterEvent userRegisterEvent)
{
//获取注册用户对象
UserBean user = userRegisterEvent.getUser();
//../省略逻辑
//输出注册用户信息
System.out.println("@EventListener注册信息,用户名:"+user.getName()+",密码:"+user.getPassword());
}
}
监听事件方法二
原生,实现ApplicationListener监听类,泛型是事件逻辑
@Component
public class RegisterListener implements ApplicationListener<UserRegisterEvent>
{
/**
* 实现监听
* @param userRegisterEvent
*/
@Override
public void onApplicationEvent(UserRegisterEvent userRegisterEvent) {
//获取注册用户对象
UserBean user = userRegisterEvent.getUser();
//../省略逻辑
//输出注册用户信息
System.out.println("注册信息,用户名:"+user.getName()+",密码:"+user.getPassword());
}
}
有序事件监听
事件监听是无序的,监听到的事件先后顺序完全随机出现的。我们接下来使用SmartApplicationListener实现监听方式来实现该逻辑。
SmartApplicationListener
接口继承了全局监听ApplicationListener
,并且泛型对象使用的ApplicationEvent
来作为全局监听,可以理解为使用SmartApplicationListener
作为监听父接口的实现,监听所有事件发布。
@Component
public class UserRegisterListener implements SmartApplicationListener
{
/**
* 该方法返回true&supportsSourceType同样返回true时,才会调用该监听内的onApplicationEvent方法
* @param aClass 接收到的监听事件类型
* @return
*/
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
//只有UserRegisterEvent监听类型才会执行下面逻辑
return aClass == UserRegisterEvent.class;
}
/**
* 该方法返回true&supportsEventType同样返回true时,才会调用该监听内的onApplicationEvent方法
* @param aClass
* @return
*/
@Override
public boolean supportsSourceType(Class<?> aClass) {
//只有在UserService内发布的UserRegisterEvent事件时才会执行下面逻辑
return aClass == UserService.class;
}
/**
* supportsEventType & supportsSourceType 两个方法返回true时调用该方法执行业务逻辑
* @param applicationEvent 具体监听实例,这里是UserRegisterEvent
*/
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
//转换事件类型
UserRegisterEvent userRegisterEvent = (UserRegisterEvent) applicationEvent;
//获取注册用户对象信息
UserBean user = userRegisterEvent.getUser();
//.../完成注册业务逻辑
System.out.println("注册信息,用户名:"+user.getName()+",密码:"+user.getPassword());
}
/**
* 同步情况下监听执行的顺序
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
通过getOrder来实现有序执行事件。
使用@Async实现异步监听
@Aysnc其实是Spring内的一个组件,可以完成对类内单个或者多个方法实现异步调用,这样可以大大的节省等待耗时。内部实现机制是线程池任务ThreadPoolTaskExecutor,通过线程池来对配置@Async的方法或者类做出执行动作。
线程任务池配置
@Configuration
@EnableAsync
public class ListenerAsyncConfiguration implements AsyncConfigurer
{
/**
* 获取异步线程池执行对象
* @return
*/
@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;
}
}
异步处理
/**
* supportsEventType & supportsSourceType 两个方法返回true时调用该方法执行业务逻辑
* @param applicationEvent 具体监听实例,这里是UserRegisterEvent
*/
@Override
@Async
public void onApplicationEvent(ApplicationEvent applicationEvent) {
try {
Thread.sleep(3000);//静静的沉睡3秒钟
}catch (Exception e)
{
e.printStackTrace();
}
//转换事件类型
UserRegisterEvent userRegisterEvent = (UserRegisterEvent) applicationEvent;
//获取注册用户对象信息
UserBean user = userRegisterEvent.getUser();
System.out.println("用户:"+user.getName()+",注册成功,发送邮件通知。");
}