在性能要求比较高的接口中,执行一个比较耗时而并不关键的操作(比如上报监控信息什么的),如果同步执行必然是没有意义的,因此一般我们会想去异步处理,通常会使用MQ之类的中间件,不过Spring也提供了事件相关的处理,就是ApplicationEvent,关于这个类这里不再多言,基础的知识可以网上搜索相关教程,不过有一个问题需要注意的是,默认这种事件机制是同步的,好处是如果有事务,发送事件的方法和事件处理的方法在同一个事务里,缺点就是,可能并没有实现我们想象中的异步处理,有一种方案是在处理事件的时候使用一个线程池,通过线程池来异步处理,虽然是解决了异步的问题,但是给笔者一种脱裤子放屁的赶脚,与其这样,还不如直接扔到一个线程池里,何必还走一个事件处理?好在Spring本身也支持ApplicationEvent的异步处理,通过@Async注解就可以了,下面是相关代码:
首先是不使用@Async注解前,ApplicationEvent处理是同步的一个验证
先来一个事件
public class UploadEvent extends ApplicationEvent {
public UploadEvent(Object source) {
super(source);
}
}
事件监听器
@Service
public class TEventListener implements ApplicationListener<UploadEvent> {
@Override
public void onApplicationEvent(UploadEvent uploadEvent) {
try {
System.out.println(">>>OK1");
TimeUnit.SECONDS.sleep(5);
System.out.println(">>>OK2");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
这里还需要用到Spring的上下文
@EnableAsync
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext; // Spring应用上下文环境
/*
*
* 实现了ApplicationContextAware 接口,必须实现该方法;
*
* 通过传递applicationContext参数初始化成员变量applicationContext
*
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtil.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static<T> T getBean(Class<T> requiredType) {
return (T) applicationContext.getBean(requiredType);
}
public static void publishEvent(ApplicationEvent event){
applicationContext.publishEvent(event);
}
}
注意这里的@EnableAsync注解,这个是后面实现异步事件的必要配置,这里先写好,后面就不再复述了。
接下来是测试类
@Test
public void testEvent(){
UploadEvent event = new UploadEvent(this);
SpringContextUtil.publishEvent(event);
System.out.println(">>>OK");
}
执行后输出的结果是
OK1
OK2
OK
明显是同步的
那么怎么办呢?很简单,在监听器方法前加一个@Async注解
@Async
@Override
public void onApplicationEvent(UploadEvent uploadEvent) {
try {
System.out.println(">>>OK1");
TimeUnit.SECONDS.sleep(5);
System.out.println(">>>OK2");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
这时再执行测试方法,结果是
OK
OK1
OK2