1.@Async注解失效可能产生的原因及解决方案
1.1.未开启异步配置
需要在SpringBoot启动类上添加@EnableAsync
注解
@SpringBootApplication@EnableAsync//开启异步线程配置publicclassAsyncDemoApplication{publicstaticvoidmain(String[] args){
SpringApplication.run(AsyncDemoApplication.class, args);}}
或者在异步线程池配置类中添加@EnableAsync
@Slf4j@EnableAsync@ConfigurationpublicclassAsyncExecutorConfigimplementsAsyncConfigurer{@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;@Overridepublic ExecutorgetAsyncExecutor(){
ThreadPoolTaskExecutor executor=newThreadPoolTaskExecutor();
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:9081spring:async-executors:core-size:100max-size:200queue-size:500
1.2.异步方法和调用者方法在同一个内中
前置条件开启了异步注解:
例如:
@Slf4j@SpringBootTestclassAsyncDemoApplicationTests{@TestvoidcontextLoads(){for(int i=0; i<10; i++){testMethod(i);}}@AsyncpublicvoidtestMethod(Integer integer){
log.info("传入的参数为:"+integer);}}
运行测试方法后输出的结果:
2021-05-1115:42:40.544 INFO16020---[ main] com.tangling.AsyncDemoApplicationTests: 传入的参数为:02021-05-1115:42:40.544 INFO16020---[ main] com.tangling.AsyncDemoApplicationTests: 传入的参数为:12021-05-1115:42:40.544 INFO16020---[ main] com.tangling.AsyncDemoApplicationTests: 传入的参数为:22021-05-1115:42:40.544 INFO16020---[ main] com.tangling.AsyncDemoApplicationTests: 传入的参数为:32021-05-1115:42:40.544 INFO16020---[ main] com.tangling.AsyncDemoApplicationTests: 传入的参数为:42021-05-1115:42:40.544 INFO16020---[ main] com.tangling.AsyncDemoApplicationTests: 传入的参数为:52021-05-1115:42:40.544 INFO16020---[ main] com.tangling.AsyncDemoApplicationTests: 传入的参数为:62021-05-1115:42:40.545 INFO16020---[ main] com.tangling.AsyncDemoApplicationTests: 传入的参数为:72021-05-1115:42:40.545 INFO16020---[ main] com.tangling.AsyncDemoApplicationTests: 传入的参数为:82021-05-1115:42:40.545 INFO16020---[ main] com.tangling.AsyncDemoApplicationTests: 传入的参数为:9
从输出结果就可以看出来异步注解没有生效,如果异步注解生效的话他输入的数字应该是乱序的。
1.3.为什么异步方法与调用者在同一个内中会失效
原因是:spring 在扫描bean的时候会扫描方法上是否包含@Async注解,如果包含,spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean的。此时,当这个有注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用时增加异步作用。然而,如果这个有注解的方法是被同一个类中的其他方法调用的,那么该方法的调用并没有通过代理类,而是直接通过原来的那个bean,所以就没有增加异步作用,我们看到的现象就是@Async注解无效。
1.4.解决办法
将异步方法按照业务统一抽取到对应的bean中,当外部需要使用时将该bean注入,然后调用bean中的异步方法
上述代码改写
异步方法工具类
@Slf4j@ComponentpublicclassAsyncUtils{@AsyncpublicvoidtestMethod(Integer integer){
log.info("传入的参数为:"+integer);}}
测试类
@Slf4j@SpringBootTestclassAsyncDemoApplicationTests{@Autowiredprivate AsyncUtils asyncUtils;@TestvoidcontextLoads(){for(int i=0; i<10; i++){
asyncUtils.testMethod(i);}}}
运行输出结果
2021-05-1115:56:11.624 INFO18424---[sync Executor-1] com.tangling.utils.AsyncUtils: 传入的参数为:02021-05-1115:56:11.624 INFO18424---[ync Executor-10] com.tangling.utils.AsyncUtils: 传入的参数为:92021-05-1115:56:11.624 INFO18424---[sync Executor-8] com.tangling.utils.AsyncUtils: 传入的参数为:72021-05-1115:56:11.624 INFO18424---[sync Executor-9] com.tangling.utils.AsyncUtils: 传入的参数为:82021-05-1115:56:11.624 INFO18424---[sync Executor-6] com.tangling.utils.AsyncUtils: 传入的参数为:52021-05-1115:56:11.624 INFO18424---[sync Executor-5] com.tangling.utils.AsyncUtils: 传入的参数为:42021-05-1115:56:11.625 INFO18424---[sync Executor-3] com.tangling.utils.AsyncUtils: 传入的参数为:22021-05-1115:56:11.625 INFO18424---[sync Executor-2] com.tangling.utils.AsyncUtils: 传入的参数为:12021-05-1115:56:11.624 INFO18424---[sync Executor-4] com.tangling.utils.AsyncUtils: 传入的参数为:32021-05-1115:56:11.624 INFO18424---[sync Executor-7] com.tangling.utils.AsyncUtils: 传入的参数为:6