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自带的注解方式只用两个注解即可实现,简单易用。当然除此之外还有其他的实现方式,例如可以通过创建线程池来实现。

  • 相关阅读:
    jQuery 基本选择器
    JavaScriptif while for switch流程控制 JS函数 内置对象
    JavaScrip基本语法
    数据库 存储引擎 表的操作 数值类型 时间类型 字符串类型 枚举集合 约束
    数据库基础知识 管理员 用户登录授权的操作
    粘包的产生原理 以及如何解决粘包问题
    socket TCP DPT 网络编程
    2018年年终总结
    Android技术分享
    No accelerator found
  • 原文地址:https://www.cnblogs.com/taich-flute/p/9565423.html
Copyright © 2011-2022 走看看