Spring中的异步任务(CompletableFuture版)

CompletableFuture vs Future

CompletableFuture可以回调,Future没有回调函数。

AsyncTaskConfig.java

java 复制代码
package com.xxxx.web.core.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

/**
 * 异步任务线程池配置
 */
@Configuration
public class AsyncTaskConfig {
    @Bean
    public Executor ocrTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(2);
        executor.setQueueCapacity(500);
        executor.setThreadNamePrefix("OCR-AsyncTask-");
        executor.initialize();
        return executor;
    }
}

Application.java

java 复制代码
@SpringBootApplication
@EnableAsync
public class Application
{
    public static void main(String[] args)
    {
        SpringApplication.run(com.miniapp.Application.class, args);
    }
}

这里主要就是配置@EnableAsync注解

OcrController.java

java 复制代码
package com.xxx.web.controller.system.api;

import com.xxx.common.core.domain.AjaxResult;
import com.xxx.system.service.ITesseractOCRService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.concurrent.CompletableFuture;

@Slf4j
@RestController
@RequestMapping("/api/ocr")
public class OcrController {


    @Resource
    private ITesseractOCRService iTesseractOCRService;

    @PostMapping("/testAsync")
    public AjaxResult recognizeTextAsync(@RequestParam("file") MultipartFile file) {
        log.info("开始recognizeTextAsync任务:{}", file.getOriginalFilename());
        CompletableFuture<String> ocrCompletableFuture = iTesseractOCRService.recognizeTextAsync(file);
        // 如果执行成功:
        ocrCompletableFuture.thenAccept((result) -> log.info("ocr任务结束:{}---{}", file.getOriginalFilename() ,result));
        // 如果执行异常:
        ocrCompletableFuture.exceptionally((e) -> {
            log.error("ocr任务异常结束", e);
            return null;
        });
        log.info("结束recognizeTextAsync任务:{}", file.getOriginalFilename());
        return AjaxResult.success();
    }
}

这里关键代码就是thenAccept异步任务完成正常回调和exceptionally异步任务执行异常回调。

ITesseractOCRService.java

java 复制代码
package com.xxxx.system.service;

import org.springframework.web.multipart.MultipartFile;

import java.util.concurrent.CompletableFuture;

/**
 * ocr识别服务
 */
public interface ITesseractOCRService {
    /**
     * ocr识别
     * @param multipartFile 上传文件对象
     * @return ocr识别字符串
     */
    String recognizeText(MultipartFile multipartFile);


    /**
     * ocr异步识别
     * @param multipartFile 上传文件对象
     * @return ocr识别字符串
     */
    CompletableFuture<String> recognizeTextAsync(MultipartFile multipartFile);
}

TesseractOCRServiceImpl.java

java 复制代码
package com.xxxx.system.service.impl;

import com.xxx.common.exception.ServiceException;
import com.xxx.system.service.ITesseractOCRService;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;

@Service
@Slf4j
public class TesseractOCRServiceImpl implements ITesseractOCRService {
    @Resource
    private Tesseract tesseract;

    @Override
    public String recognizeText(MultipartFile multipartFile) {
        try {
            BufferedImage image = ImageIO.read(multipartFile.getInputStream());
            return tesseract.doOCR(image);
        } catch (TesseractException e) {
            log.error("OCR识别异常:{}", multipartFile.getOriginalFilename(), e);
            throw new ServiceException(String.format("OCR识别异常:%s", multipartFile.getOriginalFilename()));
        } catch (IOException e) {
            log.error("OCR读文件异常", e);
            throw new ServiceException(String.format("OCR读文件异常:%s", multipartFile.getOriginalFilename()));
        }
    }

    @Async("ocrTaskExecutor")
    @Override
    public CompletableFuture<String> recognizeTextAsync(MultipartFile multipartFile) {
        log.info("开始Ocr图片任务{}", multipartFile.getOriginalFilename());
        String results = this.recognizeText(multipartFile);
        log.info("完成Ocr图片任务{}", multipartFile.getOriginalFilename());
        return CompletableFuture.completedFuture(results);
    }
}

这里关键代码就是@Async("ocrTaskExecutor")表示方法使用ocrTaskExecutor线程池来运行;CompletableFuture.completedFuture来返回正常异常任务执行完成。

总结

CompletableFuture的回调方式,大大简化了Spring异步任务处理实现。

参考

相关推荐
小马爱打代码2 分钟前
Spring Boot :使用 Spring Cache 注解方式集成 Redis
spring boot·redis·spring
坊钰3 分钟前
【Rabbit MQ】Rabbit MQ 介绍
java·rabbitmq
雀啼春10 分钟前
Java中的数据类型
java
80530单词突击赢19 分钟前
C++关联容器深度解析:set/map全攻略
java·数据结构·算法
兩尛26 分钟前
c++知识点1
java·开发语言·c++
东东51628 分钟前
果园预售系统的设计与实现spingboot+vue
前端·javascript·vue.js·spring boot·个人开发
舟舟亢亢28 分钟前
JVM复习笔记——下
java·jvm·笔记
rainbow688930 分钟前
Python学生管理系统:JSON持久化实战
java·前端·python
有味道的男人43 分钟前
1688获得商品类目调取商品榜单
java·前端·spring