SpringBoot项目使用自带的@Async异步处理功能实现业务逻辑的异步调用
物料准备:
1.配置启用SpringBoot内置的@EnableAsync功能
2.定义async任务执行需要的线程池配置
3.定义具体的async方法,可以是无返回值的void方法,也可以是有返回值的方法
在启动类上配置@EnableAsync
也可以单独写个@Configuration配置类,在上面加@EnableAsync注解。但是实际开发常常直接配置到app启动类上
@SpringBootApplication
@EnableAsync //启用 SpringBoot内置的Async功能
public class KnowWikiBackendApplication {
public static void main(String[] args) {
SpringApplication.run(KnowWikiBackendApplication.class, args);
}
}
自定义一个AsyncConfig类来配置async任务执行需要的线程池
@Configuration
public class AsyncConfig {
@Bean("asyncCountTestTaskExecutor")
public ThreadPoolTaskExecutor asyncCountTaskTest(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程数5:线程池创建时候初始化的线程数
executor.setCorePoolSize(5);
//最大线程数10:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(10);
//缓冲队列100:用来缓冲执行任务的队列
executor.setQueueCapacity(100);
//允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
executor.setKeepAliveSeconds(60);
//线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
executor.setThreadNamePrefix("countTestTaskAsync-");
//线程池满了后新任务由 任务发起者的线程执行
RejectedExecutionHandler callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();
executor.setRejectedExecutionHandler(callerRunsPolicy);
executor.initialize();
return executor;
}
@Bean("asyncVoidTestTaskExecutor")
public ThreadPoolTaskExecutor asyncVoidTaskTest(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程数5:线程池创建时候初始化的线程数
executor.setCorePoolSize(5);
//最大线程数10:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(10);
//缓冲队列100:用来缓冲执行任务的队列
executor.setQueueCapacity(100);
//允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
executor.setKeepAliveSeconds(60);
//线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
executor.setThreadNamePrefix("voidTestTaskAsync-");
//线程池满了后新任务由 任务发起者的线程执行
RejectedExecutionHandler callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();
executor.setRejectedExecutionHandler(callerRunsPolicy);
executor.initialize();
return executor;
}
}
自定义一个类AsyncAllService实现具体的async方法逻辑
@Service
@Slf4j
public class AsyncAllService {
@Async("asyncCountTestTaskExecutor")
public Future<Long> testCount1(){ //注意要使用Future接口包括起来返回的类型
String now = DateUtil.now();
log.info("now:{}",now);
log.info("---exec testCount1------------");
String input1 = "aweff2 eawf 3ww 3w5g ref 3w4gaerfg vq34efqgv3 qvg egv23rg aref 3aewe2r3 ewer2";
String input2 = "w";
String s1 = input1.toUpperCase();
String s2 = input2.toUpperCase();
//字符s2 出现的次数
//把s1中的s2都替换成空后的字符串s3
String s3 = s1.replaceAll(s2, "");
//s1-s3的长度就是s2出现的次数
long count = input1.length() - s3.length();
return new AsyncResult<Long>(count); //这里使用 AsyncResult接收执行结束返回的值, AsyncResult是spring提供的一个异步返回值包装器, AsyncResult实现了jdk里的Future
}
@Async("asyncVoidTestTaskExecutor")
public void testAsync2(){
String now = DateUtil.now();
log.info("now:{}",now);
log.info("---exec testAsync2------------");
}
}
在controller中写个API调用这2个异步任务
@Slf4j
@RestController
@RequestMapping("/third")
public class TestApi {
@Autowired
private AsyncAllService asyncAllService;
@GetMapping("/t1")
public String te() throws ExecutionException, InterruptedException {
log.trace("trace---test!!!!!");
log.info("info---test!!!!!");
log.warn("warn---test!!!!!");
log.debug("debug---test!!!!!");
log.error("error---test!!!!!");
//有返回值的async任务
Future<Long> longFuture = asyncAllService.testCount1();
//无返回值的async任务
asyncAllService.testAsync2();
//有返回值的async任务,需要多个future都执行后,最后统一get返回值
Long l605 = longFuture.get();
log.info("async task res:{}",l605);
return "thirdTestApi测试!";
}
}
测试执行效果
2023-06-05 19:02:05,596 INFO [countTestTaskAsync-1] [f2ce98d2-10ed-490f-b773-06c07ecb86c8] c.a.k.a.b.AsyncAllService [AsyncAllService.java : 35] now:2023-06-05 19:02:05
2023-06-05 19:02:05,597 INFO [countTestTaskAsync-1] [f2ce98d2-10ed-490f-b773-06c07ecb86c8] c.a.k.a.b.AsyncAllService [AsyncAllService.java : 36] ---exec testCount1------------
2023-06-05 19:02:05,596 INFO [voidTestTaskAsync-1] [f2ce98d2-10ed-490f-b773-06c07ecb86c8] c.a.k.a.b.AsyncAllService [AsyncAllService.java : 53] now:2023-06-05 19:02:05
2023-06-05 19:02:05,599 INFO [voidTestTaskAsync-1] [f2ce98d2-10ed-490f-b773-06c07ecb86c8] c.a.k.a.b.AsyncAllService [AsyncAllService.java : 54] ---exec testAsync2------------
通过日志可以看到,2个异步方法 实现了并发执行。