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

参考

相关推荐
雨中飘荡的记忆1 天前
Spring AI 1.0实战:构建基于DeepSeek的智能客服系统
spring·ai编程
野生技术架构师1 天前
TokenRetryHelper 详解与 Spring Boot 迁移方案
java·spring boot·后端
蚰蜒螟1 天前
Redis网络层深度解析:数据如何写回客户端
java·开发语言·bootstrap
廋到被风吹走1 天前
【Java】新特性最佳实践:避坑指南与性能优化
java·性能优化
ziyue75751 天前
idea不能使用低版本插件问题解决
java·ide·intellij-idea
IT 行者1 天前
告别硬编码!Spring Boot 优雅实现 Controller 路径前缀统一管理
数据库·spring boot·python
蓝程序1 天前
Spring AI学习 程序接入大模型(框架接入)
人工智能·学习·spring
牛奔1 天前
Kubernetes 节点安全维护全流程:从驱逐 Pod 到彻底清理残留
java·安全·云原生·容器·kubernetes
disgare1 天前
关于分布式系统 RPC 中高可用功能的实现
java·分布式