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异步任务处理实现。

参考

相关推荐
KhalilRuan14 分钟前
UnityCsReference——笔记
java·开发语言·笔记
何以解忧,唯有..39 分钟前
SpringBoot 中 @Transactional 注解失效的 8 种常见场景与解决方案
java
SL-staff1 小时前
AB测试数据失真根因与变量热替换实战:JVS-Rules函数计算器架构解析
java·运维·微服务·函数式编程·规则引擎·变量管理·营销技术
Irene19911 小时前
Java 3 天入门:“最小必要知识”的功利性学法
java
长谷深风1111 小时前
Agent 何时该 Replan:五个关键判断
java·大数据·开发语言·ai agent·ai智能体·agent设计·clarify机制
阿弱1 小时前
graph-core 的边与命令模式设计
java·后端·agent
互联网中的一颗神经元1 小时前
01. Go 内存管理全景架构
java·jvm·golang
萧瑟余晖1 小时前
Java深入解析篇三十四之分布式事务
java·开发语言·分布式
CAE虚拟与现实2 小时前
源码注解 /class 注解 / 运行时注解三者生命周期
java·开发语言