zoukankan      html  css  js  c++  java
  • SpringBoot异步处理请求

       在实际项目中需要开发一个处理资源编译请求的接口:接受前台页面上传的ymal文件,后台根据模板生成scala文件,然后打包、构建docker镜像。

    文件上传和后台处理过程的实现都不难,只是整个过程是比较耗时的,这里如果使用同步方式,那么上传-->模板解析-->打包-->构建镜像-->返回结果;这个过程,前台的页面都是等待状态的,用户会以为页面卡死了。所以,这里需要做异步处理:

    1.上传-->返回正在编译的标志;

    2.模板解析-->打包-->构建镜像-->存储编译结果;

    此时,当用户上传完文件后,页面立马跳转,模板解析和镜像构建等工作,继续在后台进行,而用户可以不用等待。

    由于整个接口服务采用springboot实现,这里简单记录一种springBoot的异步使用方式,

      这种方式,是springBoot自身的一种异步方式,使用注解实现,非常方便,我们在想要异步执行的方法上加上@Async注解,在controller上加上@EnableAsync即可。注意这里的异步方法,只能在自身之外调用,在本类调用是无效的。

    controller

    @RequestMapping(value = "/XXX/xxx")
    @RestController
    @EnableAsync
    public class CompileController {
        private static final Logger log = LoggerFactory.getLogger(CompileController.class);
    
        private final static int MZX_SIZE = 51200000;
    
        @Autowired
        private CompileRecordRepository recordRepository;
    
        @Autowired
        private BackendService backend;
    
    
        @Value("${build.resource-dir}")
        private String resourceDir;
    
        /**
         * 编译服务
         *
         * @param name
         * @param version
         * @param namespace
         * @param file
         * @return
         */
        @RequestMapping(value = "/compile", method = RequestMethod.POST)
        public String compile(String name, String version, String namespace, @RequestParam("yaml") MultipartFile file) {
            if (file.isEmpty()) {
                return Response.error("编译失败,因为文件是空的.");
            }
            if (file.getSize() > MZX_SIZE) {
                return Response.error("编译失败,文件大小超過限制");
            }
    
            String fileName = file.getOriginalFilename().toLowerCase();
            log.info("fileName:" + fileName);
    
            if (!fileName.endsWith(".yml")) {
                return Response.error("must upload yml format file");
            }
    
            String token = TokenUtil.generateToken();
            CompileLog compileLog = new CompileLog();
            compileLog.setId(token);
            compileLog.setName(name);
            compileLog.setNamespace(namespace);
            compileLog.setToken(token);
            compileLog.setVersion(version);
            compileLog.setCreateTime(System.currentTimeMillis());
            compileLog.setUpdateTime(System.currentTimeMillis());
            compileLog.setStatus(0);
            recordRepository.save(compileLog);
    
            //读取文件内容并写到本地
            String ymlStr = readAndWrite2Local(file);
            //后台异步执行
            backend.execute(compileLog, ymlStr);
    
            return Response.Builder
                    .success()
                    .setMsg("正在编译,可根据token查询编译结果")
                    .appendData("token", token)
                    .build();
        }
    }

    serviceImpl

    @Component
    public class BackendService {
        private static final Logger log = LoggerFactory.getLogger(BackendService.class);
    
        @Autowired
        CompileRecordRepository recordRepository;
    
        @Value("${build.resource-dir}")
        String resourceDir;
    
        private final static String SCALA_FILE = "";
    
        @Async
        public String execute(CompileLog compileLog, String ymlStr) {
    
            //模板代码目录
            String capTemplateDir = resourceDir + "/cap";
            String capInstanceDir = resourceDir + "/capInstance/" + compileLog.getToken();
            FileUtil.mkdir(capInstanceDir);
            capInstanceDir += "/cap";
            //创建实例代码目录
            FileUtil.copyDir(capTemplateDir, capInstanceDir);
    
            log.info(Thread.currentThread().getName() + " start rendering...");
            TemplateService.templateRender(ymlStr, capInstanceDir + SCALA_FILE);
    
            this.pack(capInstanceDir, compileLog);
            this.image(capInstanceDir, compileLog);
          
            log.info(Thread.currentThread().getName() + " update record...");
            compileLog.setStatus(CompileStatus.SUCCESS);
            compileLog.setUpdateTime(System.currentTimeMillis());
            recordRepository.save(compileLog);
    
            log.info(Thread.currentThread().getName() + " execute finished.");
            return "执行异步任务完毕";
        }
    
    
        /**
         * 打成jar包
         */
        private void pack(String capDir, CompileLog record) {
            log.info("start package jar...");
        
        }
    
        /**
         * 生成镜像
         */
        private void image(String capDir, CompileLog record) {
            log.info("start build docker image...");
    
        }
    }

    执行结果,略。。。。。。

    很多情况下,异步处理是一种很常见而且高效的方式,springBoot自带的注解方式只用两个注解即可实现,简单易用。当然除此之外还有其他的实现方式,例如可以通过创建线程池来实现。

  • 相关阅读:
    A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list.
    leetcode算法
    leetcode
    UVA 11076 Add Again
    UVA 10892 LCM Cardinality
    HDU 5961 传递
    UVALive 7040 Color
    2014ACM/ICPC亚洲区广州站题解
    HDU 5136 Yue Fei's Battle
    HDU 5129 Yong Zheng's Death
  • 原文地址:https://www.cnblogs.com/taich-flute/p/9565423.html
Copyright © 2011-2022 走看看