事件创建

自定义事件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();
        //...省略逻辑
    }
}

注意:如果存在多个监听器监听同一个事件时,并且存在异步与同步同时存在时则不存在执行顺序。外部事务对异步方法无效,异步方法内部若调用其他带事务的方法时事务能正常控制。