spring异步框架使用教程

这篇具有很好参考价值的文章主要介绍了spring异步框架使用教程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

在需求开发过程中,为了提升效率,很容易就会遇到需要使用多线程的场景。这个时候一般都会选择建一个线程池去专门用来进行某一类动作,这种任务到来的时候往往伴随着大量的线程被创建调用。而还有另外一种场景是整个任务的执行耗时比较长,但又不适合起多线程去运行,只能后台起一个异步线程去慢慢跑。这个时候就需要一个公共的线程池。

可选方案

总体思想就是要有一个全局可用的线程池,可以用来执行一些零散的任务。

方案一

自定义一个全局的线程池,需要异步操作的就调用。这种方法好处是实现简单,并且调用起来也简单,直接当成一个方法就可以了。但需要同模块项目(或者导入了模块)才能使用。

方案二

使用Spring自带的注解@Async实现异步。这种方法的好处是注解可以跨模块使用,因为线程池对象会被注入容器,整个服务共用。而且更大的好处是使用简单,使用者只需要给所需异步操作的方法加上@Async(“beanName”)即可。其中beanName是指注入容器的对象的名称,也可以不加参数,不加参数代表使用默认线程池。

考虑到便捷性和新手友好性,选择了方案二。

实现(注意看我的调用的结构,可以避免循环依赖)

controller->async->service √
controller->service->async->service ×,这样会出现循环依赖

1.创建线程池配置类
/**
*	必须加上@EnableAsync注解
*/
@EnableAsync
@Configuration
public class TaskPoolConfig {
	/**
	*	可以多创建几个bean注入容器,根据bean不同用来执行不同类型的任务
	*/
    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程池大小
        executor.setCorePoolSize(16);
        //最大线程数
        executor.setMaxPoolSize(20);
        //配置队列容量,默认值为Integer.MAX_VALUE
        executor.setQueueCapacity(99999);
        //活跃时间
        executor.setKeepAliveSeconds(60);
        //线程名字前缀
        executor.setThreadNamePrefix("asyncServiceExecutor -");
        //设置此执行程序应该在关闭时阻止的最大秒数,以便在容器的其余部分继续关闭之前等待剩余的任务完成他们的执行
        executor.setAwaitTerminationSeconds(60);
        //等待所有的任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }


	@Bean("taskExecutor2")
    public Executor taskExecutor2() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程池大小
        executor.setCorePoolSize(16);
        //最大线程数
        executor.setMaxPoolSize(20);
        //配置队列容量,默认值为Integer.MAX_VALUE
        executor.setQueueCapacity(99999);
        //活跃时间
        executor.setKeepAliveSeconds(60);
        //线程名字前缀
        executor.setThreadNamePrefix("asyncServiceExecutor -");
        //设置此执行程序应该在关闭时阻止的最大秒数,以便在容器的其余部分继续关闭之前等待剩余的任务完成他们的执行
        executor.setAwaitTerminationSeconds(60);
        //等待所有的任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}
2.使用异步

异步类:

public interface AsyncService {
	void test();
}
@Slf4j
@Service
public class AsyncServiceImpl implements AsyncService {
 	@Autowired
    private TestService testService;
    //这里的参数是只bean的名称,不填则使用默认的线程池。如果这个注解放在类上,代表这个类里面的全部方法都走异步
	@Async("taskExecutor")
	void test(){
		testService.todo();
	}
	
	@Async("taskExecutor2")
	void test2(){
		testService.todo2();
	}
}

业务类:

public interface TestService {
	void todo();
	void todo2();
}
@Slf4j
@Service
public class TestServiceImpl implements TestService{
    
	void todo(){
		LocalDateTime dateTime=LocalDateTime.now();
		log.info("已经进入异步方法,现在时间:{},睡三秒",dateTime);
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		dateTime=LocalDateTime.now();
		log.info("三秒后时间为:{}",dateTime);
	}
	void todo2(){
	}
}

测试类:

@Slf4j
@RestController
public class TestController {
	@Autowired
	private AsyncService asyncService;
	@RequestMapping("/test")
	public void test(){
		asyncService.test();
		LocalDateTime dateTime=LocalDateTime.now();
		log.info("这是主线程,现在时间为:{}",dateTime);
	}
}

结果:成功
spring异步框架使用教程,spring,spring boot

坑点

1.异步失效

如果一个类里面有两个方法A、B,方法B添加了异步注解,方法A调用方法B,异步不会生效。
查了一下,好像是因为异步注解的实现用到了动态代理,而一个类内部方法的调用不会走代理,也就没法实现异步。
因此,建议把异步都放在一个专门的异步类里面,这个类的方法只用来实现异步,方法内部再去调用真正的业务逻辑方法。

2.循环依赖

正常来说,A类中注入B类对象,B类中再注入A类对象。这种情况在代码中并不会发生循环依赖。而在异步注解中会出现循环依赖,因为异步注解底层实现用的是动态代理。文章来源地址https://www.toymoban.com/news/detail-664731.html

到了这里,关于spring异步框架使用教程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Boot异步任务、异步消息

    目录 1.异步任务 1.1.概述 1.2.使用 2.异步消息 2.1.概述 2.2.使用 举一个例子,我现在有一个网上商城,客户在界面点击下单后,后台需要完成两步: 1.创建客户订单 2.发短信通知客户订单号 这里面第2步是个高耗时的操作,如果全部挤在一条主线程里做,效果就会是客户点了一

    2023年04月22日
    浏览(38)
  • Spring Boot 数据访问框架介绍及使用

    Spring Boot 是一个流行的 Java 应用程序框架,它提供了许多工具和库,帮助开发人员快速构建高效的应用程序。其中,Spring Boot 数据访问框架是其中一个重要的组件,它提供了许多不同的选项,以便开发人员能够与各种不同的数据源进行交互。在本文中,我们将介绍 Spring Boot

    2024年02月13日
    浏览(28)
  • 【Spring云原生系列】Spring RabbitMQ:异步处理机制的基础--消息队列 原理讲解+使用教程

    🎉🎉 欢迎光临,终于等到你啦 🎉🎉 🏅我是 苏泽 ,一位对技术充满热情的探索者和分享者。🚀🚀 🌟持续更新的专栏 《Spring 狂野之旅:从入门到入魔》 🚀 本专栏带你从Spring入门到入魔   这是苏泽的个人主页可以看到我其他的内容哦👇👇 努力的苏泽 http://suzee.blog.

    2024年03月15日
    浏览(38)
  • Spring Boot 如何实现异步消息处理

    在现代应用程序中,异步消息处理是一项至关重要的任务。它可以提高应用程序的性能、可伸缩性和可靠性,同时也可以提供更好的用户体验。Spring Boot提供了多种方式来实现异步消息处理,包括使用Spring AMQP、Spring Kafka和Spring JMS等。本文将介绍如何使用Spring Boot实现异步消息

    2024年02月07日
    浏览(30)
  • Spring Boot实现对超大文件进行异步压缩下载

     在Web应用中,文件下载功能是一个常见的需求,特别是当你需要提供用户下载各种类型的文件时。本文将演示如何使用Spring Boot框架来实现一个简单而强大的文件下载功能。我们将创建一个RESTful API,通过该API,用户可以下载问价为ZIP压缩文件。 首先,确保你已经创建了一个

    2024年02月07日
    浏览(35)
  • Spring boot使用gRPC 的详细教程

    本篇文章,我们介绍gRPC并通过例子详细演示使用gRPC的过程。 微信搜索关注《Java学研大本营》,加入读者群,分享更多精彩 gRPC是一个开源的、高性能的远程过程调用(RPC)框架,由谷歌提供,用于分布式系统之间的高效通信。它使用协议缓冲区(protobuf)进行有效的数据序

    2024年01月22日
    浏览(21)
  • Spring Boot中配置文件介绍及其使用教程

    目录 一、配置文件介绍 二、配置简单数据 三、配置对象数据 四、配置集合数据 五、读取配置文件数据 六、占位符的使用 SpringBoot项目中,大部分配置都有默认值,但如果想替换默认配置的话,就可以使用application.properties或者application.yml或者application.yaml进行配置。SpringBo

    2024年02月08日
    浏览(35)
  • Spring Boot 整合 Redis 全面教程:从配置到使用

    Redis 是一种高性能的键值存储数据库,而 Spring Boot 是一个简化了开发过程的 Java 框架。将两者结合,可以轻松地在 Spring Boot 项目中使用 Redis 来实现数据缓存、会话管理和分布式锁等功能。 在 pom.xml 文件中添加 Redis 相关依赖 在 application.properties 或 application.yml 配置文件中添

    2024年02月13日
    浏览(28)
  • Spring Boot - Application Events 同步 VS 异步 发布订阅事件实战

    Spring Boot - Application Events 的发布顺序_ApplicationStartingEvent Spring Boot - Application Events 的发布顺序_ApplicationEnvironmentPreparedEvent Spring Boot - Application Events 的发布顺序_ApplicationContextInitializedEvent Spring Boot - Application Events 的发布顺序_ApplicationPreparedEvent Spring Boot - Application Events 的发布顺

    2024年01月17日
    浏览(45)
  • Spring Boot框架中Controller层API接口如何支持使用多个@RequestBody注解接受请求体参数

    众所周知,在Spring Boot框架中,Controller层API接口编码获取请求体参数时,在参数上会使用@RequestBody注解;如果一次请求中,请求体参数携带的内容需要用多个参数接收时,能不能多次使用@RequestBody注解呢? 下面我们先测试一下,参考代码: PostMan进行请求: 服务端后端日志:

    2024年01月17日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包