Spring ApplicationEvent 异步处理

在性能要求比较高的接口中,执行一个比较耗时而并不关键的操作(比如上报监控信息什么的),如果同步执行必然是没有意义的,因此一般我们会想去异步处理,通常会使用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

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring注解@Async用于标注在方法上,以实现异步地调用该方法。通过该注解标记的方法,在被调用时会立即返回,而实际的方法执行将会被提交给Spring的TaskExecutor任务中,由指定的线程池中的线程来执行。 对于Spring中的@Async注解,默认的线程池和异步处理方法是空的,所以在使用@Async注解时,需要指定一个线程池来执行异步任务。可以通过继承或重新实现AsyncConfigurer接口中的getAsyncExecutor()方法来自定义线程池。 关于Spring注解驱动开发,《Spring注解驱动开发》是一套教程,可以帮助我们深入了解Spring的原理和机制。在现今的技术中,比如SpringBoot和SpringCloud等,它们大量使用了Spring的底层注解和原理,如@Conditional、@Import等。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Spring之@Async异步注解](https://blog.csdn.net/sun134911/article/details/119677348)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [通俗易懂的Spring注解驱动开发教程(含配套资料)](https://download.csdn.net/download/weixin_26970501/19650011)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值