SpringBoot @Async 注解无效
发布日期:2021-06-30 12:36:57 浏览次数:3 分类:技术文章

本文共 3868 字,大约阅读时间需要 12 分钟。

开发环境
  • SpringBoot 2.1.10.RELEASE
  • JDK 1.8
场景

在一个类的方法中,调用同类的异步方法无效,例如以下示例:

package com.nobody.controller;import java.util.concurrent.TimeUnit;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;@RestController@RequestMapping("demo")public class DemoController {
@GetMapping("test") public void test() {
asyncTask(); System.out.println("主线程 Thread name:" + Thread.currentThread().getName()); } @Async public void asyncTask() {
try {
TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {
e.printStackTrace(); } System.out.println("异步方法 Thread name:" + Thread.currentThread().getName()); }}

启动类也添加@EnableAsync注解

package com.nobody;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.scheduling.annotation.EnableAsync;@SpringBootApplication@EnableAsyncpublic class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args); }}

输出结果:

异步方法 Thread name:http-nio-9563-exec-1主线程 Thread name:http-nio-9563-exec-1

从结果分析,明显是串行单线程执行。

原因分析

类内部方法调用时,直接进行内部调用,没有走Spring的代理类。Async注解的实现都是基于Spring的AOP,而AOP的实现是基于动态代理模式实现的。调用方法的是对象本身而不是代理对象,没有经过Spring容器。

解决方案

新建一个类,通过注解让Spring容器管理,然后在调用类中注入对象。

package com.nobody.domain;import java.util.concurrent.TimeUnit;import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Service;@Servicepublic class AsyncService {
@Async public void asyncTask() {
try {
TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {
e.printStackTrace(); } System.out.println("异步方法 Thread name:" + Thread.currentThread().getName()); }}
package com.nobody.controller;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 com.nobody.domain.AsyncService;@RestController@RequestMapping("demo")public class DemoController {
@Autowired private AsyncService asyncService; @GetMapping("test") public void test() {
asyncService.asyncTask(); System.out.println("主线程 Thread name:" + Thread.currentThread().getName()); }}

输出结果:

主线程 Thread name:http-nio-9563-exec-1异步方法 Thread name:task-1

如果异步方法非要写在同一个类中,可以懒加载注入本类的实例,进行调用,例如:

package com.nobody.controller;import java.util.concurrent.TimeUnit;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Lazy;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;@RestController@RequestMapping("demo")public class DemoController {
@Autowired @Lazy // 懒加载注入,不加会报错 private DemoController demoController; @GetMapping("test") public void test() {
// 通过DemoController实例调用 demoController.asyncTask(); System.out.println("主线程 Thread name:" + Thread.currentThread().getName()); } // 方法不能是private类型,不然还是串行单线程执行 @Async public void asyncTask() {
try {
TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {
e.printStackTrace(); } System.out.println("异步方法 Thread name:" + Thread.currentThread().getName()); }}

输出结果:

主线程 Thread name:http-nio-9563-exec-1异步方法 Thread name:task-1

转载地址:https://javalib.blog.csdn.net/article/details/106276893 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:并发编程 线程池以及@Async注解的使用
下一篇:对线程中未捕获的异常进行处理UncaughtExceptionHandler

发表评论

最新留言

很好
[***.229.124.182]2024年04月13日 20时40分46秒