• Spring中异步方法的使用


    Spring中异步方法的使用

    1. 异步方法描述

    异步方法,顾名思义就是调用后无须等待它的执行,而继续往下执行;@Async是Spring的一个注解,在Spring Boot中,我们只需要使用@Async注解就能简单的将原来的同步函数变为异步函数。

    对于比较耗时的操作,我们可以抽取成异步方法来让主线程稳定快速继续执行,对于异步方法的执行结果可根据自己的要求是否需要在主线程处理;

    2. 异步方法的实现步骤

    在springboot应用我们可以使用简单的两个注解即可开启并使用异步方法;

    1. 创建一个普通的Service类,并有@Service修饰,表示这个服务类交给Spring管理;
    2. 在Service方法里定义一个普通的方法,使用@Async修饰;表示这是一个异步方法;
    3. 在引导类中添加@EnableAsync注解,使应用开启对异步方法的支持;

    3. 实测一下

    3.1 定义个Service类

    @Slf4j
    @Service
    public class MyAsyncSevice {
    
        @Async
        public void myAsyncMehtod(){
            log.info("---> enter aysnc method");
            try {
                Thread.sleep(5000);
                int i = 1/0;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("---> end of async method");
        }
    }
    

    3.2 定义个测试Controlle

    @Slf4j
    @RestController
    public class AsyncContorller {
    
        // 注入异步方法所在的类
        @Autowired
        MyAsyncSevice myAsyncSevice;
    
        @GetMapping("/async-test")
        public String asyncTest(){
            log.info("--> enter controller");
            myAsyncSevice.myAsyncMehtod();
            log.info("--> end of controller");
            return "hello";
        }
    }
    

    3.3 在启动类上启用异步

    @EnableAsync
    @SpringBootApplication
    public class JsrDemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(JsrDemoApplication.class, args);
        }
    
    }
    

    3.4 测试

    可以看到输出,controlle中调用了异步方法后继续执行,即使异步方法报错也不会controller的执行;

    curl -X GET -H   "http://localhost:8080/async-test"
    
    2021-08-20 17:42:50.810   --- [nio-8080-exec-1] AsyncContorller  : --> enter controller
    2021-08-20 17:42:50.813   --- [nio-8080-exec-1] AsyncContorller  : --> end of controller
    2021-08-20 17:42:50.821   --- [         task-1] MyAsyncSevice  : ---> enter aysnc method
    2021-08-20 17:42:55.832   --- [         task-1] MyAsyncSevice  : ---> end of async method
    

    4. 补充

    4.1 Executor线程池

    上面的测试,我们并没有创建新的线程和线程池,如果我们不配置线程池的Bean,Spring会自动创建SimpleAsyncTaskExecutor,并使用它来执行异步方法。定义线程池bean可参考如下:

    @Bean
    public Executor taskExecutor() {
     	ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
     	executor.setCorePoolSize(3);
     	executor.setMaxPoolSize(3);
     	executor.setQueueCapacity(500);
     	executor.setThreadNamePrefix("MyThreadPool");
     	executor.initialize();
     	return executor;
    }
    

    4.2 异步返回Futrue

    4.2.1 这样改造我们的异步方法,即返回一个Futrue类型的结果;

        @Async
        public Future myAsyncMehtod(){
            log.info("---> enter aysnc method");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("---> end of async method");
    
            return new AsyncResult("I am async method result");
        }
    

    4.2.2 Contorller也改造下

    使用了Futrue.get方法,controller主线程就会等待异步方法的执行结束,或等待超时后才会结束。

    	@GetMapping("/async-test")
        public String asyncTest(){
            log.info("--> enter controller");
            Future ft = myAsyncSevice.myAsyncMehtod();
            try {
                ft.get(1000, TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                e.printStackTrace();
            }
            log.info("--> end of controller");
            return "hello";
        }
    

    4.3 其他注意事项

    • 在同一个类中的方法调用,添加@async注解是失效的。原因是当你在同一个类中的时候,方法调用是在类中执行的,spring无法截获这个方法调用,也就不会在代理类里执行。
    • 可能会导致循环依赖,spring本身会解决循环依赖,但是因为@Async使用代理模式,spring在检查第二级缓存和原始对象是否相等时发现不相等,会抛出异常。
    • 无法获取请求上下文。
    边系鞋带边思考人生.
  • 相关阅读:
    第十章 Ingress
    第九章 Service
    第八章 资源控制器
    第一章 Xshell5评估期已过问题
    第七章 yaml格式
    第六章 资源清单
    第五章 配置私有仓库Harbor
    第四章 K8s部署安装
    36 SpringBoot 在系统配置文件中动态加载配置
    Java 集合、数组 任意个数数字相加等于一个指定的数
  • 原文地址:https://www.cnblogs.com/crazytrip/p/15167593.html
Copyright © 2020-2023  润新知