@Async注解失效可能产生的原因及解决方案

Posted Tang.Mr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了@Async注解失效可能产生的原因及解决方案相关的知识,希望对你有一定的参考价值。

1.@Async注解失效可能产生的原因及解决方案

1.1.未开启异步配置

需要在SpringBoot启动类上添加@EnableAsync注解

@SpringBootApplication
@EnableAsync//开启异步线程配置
public class AsyncDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(AsyncDemoApplication.class, args);
    }
}

或者在异步线程池配置类中添加@EnableAsync

@Slf4j
@EnableAsync
@Configuration
public class AsyncExecutorConfig implements AsyncConfigurer {

    @Value("${spring.async-executors.core-size}")
    private String CORE_SIZE;

    @Value("${spring.async-executors.max-size}")
    private String MAX_SIZE;

    @Value("${spring.async-executors.queue-size}")
    private String QUEUE_SIZE;

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(Integer.parseInt(CORE_SIZE));
        executor.setMaxPoolSize(Integer.parseInt(MAX_SIZE));
        executor.setQueueCapacity(Integer.parseInt(QUEUE_SIZE));
        executor.setThreadNamePrefix("Spring Async Executor-");
        executor.setRejectedExecutionHandler(
                (runnable, threadPoolExecutor) -> {
                    try {
                        threadPoolExecutor.getQueue().put(runnable);
                    } catch (InterruptedException e) {
                        log.info("Thread pool receives InterruptedException: " + e);
                    }
                });
        executor.initialize();
        return executor;
    }
}
server:
  port: 9081
spring:
  async-executors:
    core-size: 100
    max-size: 200
    queue-size: 500

1.2.异步方法和调用者方法在同一个内中

前置条件开启了异步注解:

例如:

@Slf4j
@SpringBootTest
class AsyncDemoApplicationTests {

    @Test
    void contextLoads() {
        for (int i = 0; i < 10; i++) {
            testMethod(i);
        }
    }
    
    @Async
    public void testMethod(Integer integer){
        log.info("传入的参数为:"+integer);
    }

}

运行测试方法后输出的结果:

2021-05-11 15:42:40.544  INFO 16020 --- [           main] com.tangling.AsyncDemoApplicationTests   : 传入的参数为:0
2021-05-11 15:42:40.544  INFO 16020 --- [           main] com.tangling.AsyncDemoApplicationTests   : 传入的参数为:1
2021-05-11 15:42:40.544  INFO 16020 --- [           main] com.tangling.AsyncDemoApplicationTests   : 传入的参数为:2
2021-05-11 15:42:40.544  INFO 16020 --- [           main] com.tangling.AsyncDemoApplicationTests   : 传入的参数为:3
2021-05-11 15:42:40.544  INFO 16020 --- [           main] com.tangling.AsyncDemoApplicationTests   : 传入的参数为:4
2021-05-11 15:42:40.544  INFO 16020 --- [           main] com.tangling.AsyncDemoApplicationTests   : 传入的参数为:5
2021-05-11 15:42:40.544  INFO 16020 --- [           main] com.tangling.AsyncDemoApplicationTests   : 传入的参数为:6
2021-05-11 15:42:40.545  INFO 16020 --- [           main] com.tangling.AsyncDemoApplicationTests   : 传入的参数为:7
2021-05-11 15:42:40.545  INFO 16020 --- [           main] com.tangling.AsyncDemoApplicationTests   : 传入的参数为:8
2021-05-11 15:42:40.545  INFO 16020 --- [           main] com.tangling.AsyncDemoApplicationTests   : 传入的参数为:9

从输出结果就可以看出来异步注解没有生效,如果异步注解生效的话他输入的数字应该是乱序的。

1.3.为什么异步方法与调用者在同一个内中会失效

描述内容参考文章

原因是:spring 在扫描bean的时候会扫描方法上是否包含@Async注解,如果包含,spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean的。此时,当这个有注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用时增加异步作用。然而,如果这个有注解的方法是被同一个类中的其他方法调用的,那么该方法的调用并没有通过代理类,而是直接通过原来的那个bean,所以就没有增加异步作用,我们看到的现象就是@Async注解无效。

1.4.解决办法

将异步方法按照业务统一抽取到对应的bean中,当外部需要使用时将该bean注入,然后调用bean中的异步方法

上述代码改写

异步方法工具类

@Slf4j
@Component
public class AsyncUtils {
    @Async
    public void testMethod(Integer integer){
        log.info("传入的参数为:"+integer);
    }
}

测试类

@Slf4j
@SpringBootTest
class AsyncDemoApplicationTests {

    @Autowired
    private AsyncUtils asyncUtils;

    @Test
    void contextLoads() {
        for (int i = 0; i < 10; i++) {
            asyncUtils.testMethod(i);
        }
    }
}

运行输出结果

2021-05-11 15:56:11.624  INFO 18424 --- [sync Executor-1] com.tangling.utils.AsyncUtils            : 传入的参数为:0
2021-05-11 15:56:11.624  INFO 18424 --- [ync Executor-10] com.tangling.utils.AsyncUtils            : 传入的参数为:9
2021-05-11 15:56:11.624  INFO 18424 --- [sync Executor-8] com.tangling.utils.AsyncUtils            : 传入的参数为:7
2021-05-11 15:56:11.624  INFO 18424 --- [sync Executor-9] com.tangling.utils.AsyncUtils            : 传入的参数为:8
2021-05-11 15:56:11.624  INFO 18424 --- [sync Executor-6] com.tangling.utils.AsyncUtils            : 传入的参数为:5
2021-05-11 15:56:11.624  INFO 18424 --- [sync Executor-5] com.tangling.utils.AsyncUtils            : 传入的参数为:4
2021-05-11 15:56:11.625  INFO 18424 --- [sync Executor-3] com.tangling.utils.AsyncUtils            : 传入的参数为:2
2021-05-11 15:56:11.625  INFO 18424 --- [sync Executor-2] com.tangling.utils.AsyncUtils            : 传入的参数为:1
2021-05-11 15:56:11.624  INFO 18424 --- [sync Executor-4] com.tangling.utils.AsyncUtils            : 传入的参数为:3
2021-05-11 15:56:11.624  INFO 18424 --- [sync Executor-7] com.tangling.utils.AsyncUtils            : 传入的参数为:6

以上是关于@Async注解失效可能产生的原因及解决方案的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot异步任务及Async不起作用的原因

Spring中异步注解@Async的使用原理及使用时可能导致的问题

Spring中异步注解@Async的使用原理及使用时可能导致的问题

@Async失效情况

关于Spring注解@Async引发其他注解失效

spring事务失效的几种场景以及原因