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

参考

相关推荐
MuYiLuck2 小时前
redis持久化与集群
java·数据库·redis
一叶飘零_sweeeet2 小时前
Java 项目 HTTP+WebSocket 统一权限控制实战
java·websocket·http·权限控制
7澄12 小时前
深入解析 LeetCode 数组经典问题:删除每行中的最大值与找出峰值
java·开发语言·算法·leetcode·intellij idea
ysyxg2 小时前
设计模式-策略模式
java·开发语言
Felix_XXXXL3 小时前
Spring Security安全框架原理与实战
java·后端
一抓掉一大把3 小时前
秒杀-StackExchangeRedisHelper连接单例
java·开发语言·jvm
升鲜宝供应链及收银系统源代码服务3 小时前
升鲜宝生鲜配送供应链管理系统--- 《多语言商品查询优化方案(Redis + 翻译表 + 模糊匹配)》
java·数据库·redis·bootstrap·供应链系统·生鲜配送·生鲜配送源代码
青山的青衫3 小时前
【JavaWeb】Tlias后台管理系统
java·web
蒟蒻的工具人3 小时前
SSE实时推送订单状态
java·eventsource·sse协议