事件创建
自定义事件AEvent继承了ApplicationEvent,继承后必须重载构造函数,构造函数的参数可以任意指定,其中source参数指的是发生事件的对象,一般我们在发布事件时使用的是this关键字代替本类对象,而a参数是我们自定义的对象,该对象可以在监听内被获取。
public class AEvent extends ApplicationEvent{
//事件传递的对象
private A a;
/**
* 重写构造函数
* @param source 发生事件的对象
* @param a 事件传递的对象
*/
public AEvent(Object source,A a) {
super(source);
this.a = a;
}
public A getA(){
return a;
}
}
事件发布
事件发布是由ApplicationContext对象管控的,我们发布事件前需要注入ApplicationContext对象调用publishEvent方法完成事件发布。
@Service
public class AServiceImpl{
@Autowired
ApplicationContext applicationContext;
public void updateA(A a){
//...省略其他逻辑
//发布AEvent事件
applicationContext.publishEvent(new AEvent(this, a));
}
}
事件监听
@EventListener注解(最常用)
@Service
public class BServiceImpl{
/**
* 注册监听实现方法
* @param aEvent 某事件
*/
@EventListener
public void aUpdated(AEvent aEvent){
//获取对象
A a = aEvent.getA();
//..省略逻辑
}
}
实现ApplicationListener泛型接口
@Service
public class BServiceImpl implements ApplicationListener<AEvent>{
/**
* 实现监听
* @param aEvent 某事件
*/
@Override
public void onApplicationEvent(AEvent aEvent){
//获取对象
A a = aEvent.getA();
//...省略逻辑
}
}
实现SmartApplicationListener接口
事件监听是无序的,若有多个监听实现,则多个监听实现被调用的顺序是随机的,若要保证监听执行的有序性则可以考虑使用实现SmartApplicationListener接口来规定执行顺序。
对于同一事件有多个不同的发布源,若你只想监听某个发布源发布的该事件,则也可以实现SmartApplicationListener接口来实现此类监听功能。
SmartApplicationListener接口继承了全局监听ApplicationListener,并且泛型对象使用ApplicationEvent来作为全局监听,可以理解为使用SmartApplicationListener作为监听父接口的实现,监听所有事件发布。SmartApplicationListener接口添加了两个方法supportsEventType、supportsSourceType来作为区分是否是我们监听的事件,只有这两个方法同时返回true时才会执行onApplicationEvent方法。
除了这两个方法,还提供了一个getOrder方法,这个方法就可以解决执行监听的顺序问题,return的数值越小证明优先级越高,执行顺序越靠前。
@Service
public class BServiceImpl implements SmartApplicationListener
{
/**
* 该方法返回true&supportsSourceType同样返回true时,才会调用该监听内的onApplicationEvent方法
* @param aClass 接收到的监听事件类型
* @return
*/
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
//只有AEvent监听类型才会执行监听逻辑
return aClass == AEvent.class;
}
/**
* 该方法返回true&supportsEventType同样返回true时,才会调用该监听内的onApplicationEvent方法
* @param aClass
* @return
*/
@Override
public boolean supportsSourceType(Class<?> aClass) {
//只有在AServiceImpl内发布的AEvent事件时才会执行监听逻辑
return aClass == AServiceImpl.class;
}
/**
* supportsEventType & supportsSourceType 两个方法返回true时调用该方法执行业务逻辑
* @param applicationEvent 具体监听实例,这里是AEvent
*/
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
//转换事件类型
AEvent aEvent= (AEvent) applicationEvent;
//获取对象
A a = aEvent.getA();
//...省略逻辑
}
/**
* 同步情况下监听执行的顺序
* @return
*/
@Override
public int getOrder() {
return 1;
}
}
异步监听
前面介绍的监听方法执行都是同步的,即事件发布之后spring会同步调用各个符合条件的监听方法,对于一些比较耗时的监听处理,可以使用@Async来实现异步监听。@Aysnc是Spring内的一个组件,可以完成对类内单个或者多个方法实现异步调用,这样可以节省等待耗时。内部实现机制是线程池任ThreadPoolTaskExecutor,通过线程池来对配置@Async的方法或者类做出执行动作。
框架已预先定义了一个名称为"listenerExecutor"支持listener的执行器ThreadPoolTaskExecutor,在需要异步监听的方法上加上@Aysnc("listenerExecutor")注解,则该方法就会被异步调用执行。
@Service
public class BServiceImpl{
/**
* 注册监听实现方法
* @param aEvent 某事件
*/
@EventListener
@Async("listenerExecutor")
public void aUpdated(AEvent aEvent){
//获取对象
A a = aEvent.getVoucher();
//...省略逻辑
}
}
注意:如果存在多个监听器监听同一个事件时,并且存在异步与同步同时存在时则不存在执行顺序。外部事务对异步方法无效,异步方法内部若调用其他带事务的方法时事务能正常控制。