解决SpringBoot中使用@Async注解失效的问题
作者:xqnode 发布时间:2023-08-24 07:38:46
错误示例,同一个类中使用异步方法:
package com.xqnode.learning.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/async")
public Map<Object, Object> test() throws InterruptedException, JsonProcessingException {
System.out.println("接收到请求。。。");
task();
Map<Object, Object> map = new HashMap<>();
System.out.println("请求结束。。。");
map.put("msg", "操作成功");
map.put("code", "0");
return map;
}
@Async
void task() throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
System.out.println("线程任务执行结束。。。");
}
}
来分析下错误的原因:
当我使用postman调用该接口的时候发现,我预想中的立即返回并没有发生。后来查询资料发现,在controller调用本类中的异步方法,不会生效
正确示例:
package com.xqnode.learning.controller;
import com.xqnode.learning.service.AsyncService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/test")
public class TestController {
private static final Logger LOG = LoggerFactory.getLogger(TestController.class);
@Autowired
private AsyncService asyncService;
@GetMapping("/async")
public Map<Object, Object> test() throws InterruptedException {
LOG.info("接收到请求。。。");
asyncService.task();
Map<Object, Object> map = new HashMap<>();
LOG.info("请求结束。。。");
map.put("msg", "操作成功");
map.put("code", "0");
return map;
}
}
将异步调用放到service中:
package com.xqnode.learning.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class AsyncService {
private static final Logger LOG = LoggerFactory.getLogger(AsyncService.class);
@Async("asyncExecutor")
public void task() throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
LOG.info("线程任务执行结束。。。");
}
}
这时候再重启项目请求该接口,就会发现接口可以立即返回值。而task任务是异步执行的,5秒之后才会打印结果:
补充知识:springboot + @Async 实现异步方法之踩坑填坑
在使用@Async注解实现异步方法的时候,我们项目中实现了AsyncConfigurer接口来自定义线程池和异常处理。其中自定义线程池的代码如上图,异常处理项目中是自定义异常类实现AsyncUncaughtExceptionHandler 接口,这里未贴出代码。那么到底踩了什么坑呢?
第一:
加了@Async注解的方法调不起来。由于我不是项目及代码的原创,花了很多时间才分析出问题。经过仔细分析,由于业务场景需要,我们在项目启动的时候就创建了3个线程(也就是创建了3个任务)这正好占满了核心线程数(3个),当调到@Async的方法时,相当于有新的任务进来,结合线程池的原理可知,新的任务都会放到阻塞队列里面去,直到阻塞队列满了才可能会创建新的线程来执行任务或者执行饱和策略(这与Runtime.getRuntime().availableProcessors()能获取到的线程数有关),所以造成了异步方法调不起来的假象。
解决方法:根据实际情况将线程池的核心线程数和最大线程数调整到合适的值。
第二:
在解决了上一个问题后,又发现了新的问题,后面某段代码看不到执行的日志,也不知道错在哪里,没有错误日志。由于之前项目的日志并不详细,在逐步完善各处日志后,终于发现问题,报出了某个实体类没有默认构造函数的错误。在@Async异步方法中有一个把json转成实体bean的操作,由于这个bean创建了有参构造函数,却没有默认的无参构造函数,所以抛异常了,正好被getAsyncUncaughtExceptionHandler()捕捉到,由于当时此方法没有日志,也是花了点时间的。
解决方法:完善日志,给实体类加上无参构造函数。
通过这两个问题,自己也总结了一下,在使用线程池相关的知识时,一定要先了解原理,不然可能给自己挖坑,还有就是平常写代码时要养成写注释和打日志的习惯,否则出问题时可能要多花很久的时间找问题。
来源:https://blog.csdn.net/xqnode/article/details/81538499
猜你喜欢
- 本文实例为大家分享了Spring实现默认标签解析流程的具体代码,供大家参考,具体内容如下承接上文,进入parseBeanDefinition
- 没有结果时,去.First()时,会报错,所以一定要先.Count()判断一下而用FirstOrDefault(),如果集合中没有数据,则返
- 1.BeanFactory1.1Spring提供了IOC容器的两种实现方式① BeanFactory:IOC容器的基本实现,是Spring内
- springboot扩展MVC自定义 config -> SpringMvcConfig.java下边就是扩展springMVC的模板
- string fileExt = Path.GetExtension(excelPath);string conn = "&quo
- 为大家分享的解决MyEclipse中的Building workspace问题的方法如下方法一:点击“Project”,取消勾选“Build
- 在实际的应用中会经常需要将数据导出成excel,导出的方式除原样导出还有分页导出、分页分sheet导出和大数据量导出。对于excel2003
- 返回集合为null还是空集合及空集合的三种写法个人认为在自己写接口时,需要返回集合时返回一个空集合,比如mybatis查询如果返回一个集合,
- 算法思想快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-
- Singleton是众多设计模式中最容易理解的一种,也是众多设计模式中较为重要的一种设计模式。接下来我们看看具体介绍。Singleton模式
- 问题:Information:java: Errors occurred while compiling module &lsquo
- 对于 * ,学过AOP的应该都不会陌生,因为代理是实现AOP功能的核心和关键技术。那么今天我们将开始 * 的学习:一、引出 * 生活中
- String类中的concat()方法的使用concat(String str)用法concat(String string) 返回值是St
- 字节流和字符流对于文件必然有读和写的操作,读和写就对应了输入和输出流,流又分成字节和字符流。1.从对文件的操作来讲,有读和写的操作——也就是
- 方式1:dependency 本地jar包<dependency> <groupId>com.jouyp
- 1|1简介最近基于最新的Activiti7配置了SpringBoot2。简单上手使用了一番。发现市面上解决Activiti7的教程很少,采坑
- 最近“全网域(Web Scale)”一词被炒得火热,人们也正在通过扩展他们的应用程序架构来使他们的系统变得更加“全网域”。但是究竟什么是全网
- 如果你还不是很了解restful,或者认为restful只是一种规范不具有实际意义,推荐一篇osc两年前的文章:RESTful API 设计
- Java常用类库Math类Math包含用于执行基本数字运算的方法,例如基本指数,对数,平方根和三角函数一、Field SummaryModi
- 在项目中经常要用到将字符串解析成Locale,但是没有一个比较好用的类。java本身提供了3个构造函数,但是实际使用过程中,需要自己解析,比