SpringBoot異步處理請求

   在實際項目中須要開發一個處理資源編譯請求的接口:接受前臺頁面上傳的ymal文件,後臺根據模板生成scala文件,而後打包、構建docker鏡像。spring

文件上傳和後臺處理過程的實現都不難,只是整個過程是比較耗時的,這裏若是使用同步方式,那麼上傳-->模板解析-->打包-->構建鏡像-->返回結果;這個過程,前臺的頁面都是等待狀態的,用戶會覺得頁面卡死了。因此,這裏須要作異步處理:docker

1.上傳-->返回正在編譯的標誌;springboot

2.模板解析-->打包-->構建鏡像-->存儲編譯結果;app

此時,當用戶上傳完文件後,頁面立馬跳轉,模板解析和鏡像構建等工做,繼續在後臺進行,而用戶能夠不用等待。異步

因爲整個接口服務採用springboot實現,這裏簡單記錄一種springBoot的異步使用方式,ui

  這種方式,是springBoot自身的一種異步方式,使用註解實現,很是方便,咱們在想要異步執行的方法上加上@Async註解,在controller上加上@EnableAsync便可。注意這裏的異步方法,只能在自身以外調用,在本類調用是無效的。this

controllerspa

@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...");

    }
}

 

執行結果,略。。。。。。scala

不少狀況下,異步處理是一種很常見並且高效的方式,springBoot自帶的註解方式只用兩個註解便可實現,簡單易用。固然除此以外還有其餘的實現方式,例如能夠經過建立線程池來實現。

相關文章
相關標籤/搜索