SpringBoot @Async 注解无效
        【摘要】     开发环境 
SpringBoot 2.1.10.RELEASEJDK 1.8 
场景 
在一个类的方法中,调用同类的异步方法无效,例如以下示例: 
package com.nobody.controller;
import java.util.concurrent.TimeUnit;
import org.springframework.scheduling.ann...
    
    
    
    开发环境
- 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()); }
}
  
 - 1
 - 2
 - 3
 - 4
 - 5
 - 6
 - 7
 - 8
 - 9
 - 10
 - 11
 - 12
 - 13
 - 14
 - 15
 - 16
 - 17
 - 18
 - 19
 - 20
 - 21
 - 22
 - 23
 - 24
 - 25
 - 26
 - 27
 - 28
 - 29
 - 30
 - 31
 - 32
 - 33
 - 34
 
启动类也添加@EnableAsync注解
package com.nobody;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}
  
 - 1
 - 2
 - 3
 - 4
 - 5
 - 6
 - 7
 - 8
 - 9
 - 10
 - 11
 - 12
 - 13
 - 14
 - 15
 - 16
 
输出结果:
异步方法 Thread name:http-nio-9563-exec-1
主线程 Thread name:http-nio-9563-exec-1
  
 - 1
 - 2
 
从结果分析,明显是串行单线程执行。
原因分析
类内部方法调用时,直接进行内部调用,没有走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;
@Service
public class AsyncService { @Async public void asyncTask() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("异步方法 Thread name:" + Thread.currentThread().getName()); }
}
  
 - 1
 - 2
 - 3
 - 4
 - 5
 - 6
 - 7
 - 8
 - 9
 - 10
 - 11
 - 12
 - 13
 - 14
 - 15
 - 16
 - 17
 - 18
 - 19
 - 20
 - 21
 - 22
 
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()); }
}
  
 - 1
 - 2
 - 3
 - 4
 - 5
 - 6
 - 7
 - 8
 - 9
 - 10
 - 11
 - 12
 - 13
 - 14
 - 15
 - 16
 - 17
 - 18
 - 19
 - 20
 - 21
 - 22
 - 23
 - 24
 - 25
 - 26
 - 27
 
输出结果:
主线程 Thread name:http-nio-9563-exec-1
异步方法 Thread name:task-1
  
 - 1
 - 2
 
如果异步方法非要写在同一个类中,可以懒加载注入本类的实例,进行调用,例如:
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()); }
}
  
 - 1
 - 2
 - 3
 - 4
 - 5
 - 6
 - 7
 - 8
 - 9
 - 10
 - 11
 - 12
 - 13
 - 14
 - 15
 - 16
 - 17
 - 18
 - 19
 - 20
 - 21
 - 22
 - 23
 - 24
 - 25
 - 26
 - 27
 - 28
 - 29
 - 30
 - 31
 - 32
 - 33
 - 34
 - 35
 - 36
 - 37
 - 38
 - 39
 - 40
 - 41
 - 42
 
输出结果:
主线程 Thread name:http-nio-9563-exec-1
异步方法 Thread name:task-1
  
 - 1
 - 2
 
文章来源: javalib.blog.csdn.net,作者:陈皮的JavaLib,版权归原作者所有,如需转载,请联系作者。
原文链接:javalib.blog.csdn.net/article/details/106276893
        【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
            cloudbbs@huaweicloud.com
        
        
        
        
        
        
        - 点赞
 - 收藏
 - 关注作者
 
            
           
评论(0)