springboot中异步接口实现所有方式_20250501

几种异步接口实现demo

package org.dromara.controller.app;


// 导入必要的依赖库

import cn.dev33.satoken.annotation.SaIgnore;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.WebAsyncTask;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.Map;
import java.util.concurrent.*;

/**
 * 异步接口实现方式大全
 * 演示Spring Boot中多种异步处理方案:
 * 1. 响应体发射器(ResponseBodyEmitter)
 * 2. 服务器发送事件(SSE)
 * 3. 文件流传输
 * 4. Callable异步调用
 * 5. WebAsyncTask
 * 6. 延迟结果(DeferredResult)
 */
@Slf4j // Lombok生成日志对象
@SaIgnore // 忽略权限校验
@RestController // REST控制器
@RequestMapping("testAsync") // 请求路径前缀
public class TestAsyncController {
    // 创建单线程定时任务线程池
    private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    // 延迟结果存储容器(线程安全)
    private static final Map<String, DeferredResult<String>> DEFERRED_RESULT_MAP = new ConcurrentHashMap<>();

    /**
     * 使用ResponseBodyEmitter实现持续通信
     * 每2秒向客户端发送时间戳消息
     */
    @GetMapping("/emitter")
    public ResponseEntity<ResponseBodyEmitter> handle() {
        // 创建响应发射器
        ResponseBodyEmitter emitter = new ResponseBodyEmitter();

        // 定时任务:每2秒发送一次消息
        scheduler.scheduleAtFixedRate(() -> {
            try {
                emitter.send(String.format("timestamp: %d\n", System.currentTimeMillis()), MediaType.TEXT_PLAIN);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }, 0, 2, TimeUnit.SECONDS); // 初始延迟0s,间隔2s

        // 设置10秒超时处理
        // 关闭连接
        emitter.onTimeout(emitter::complete);

        return new ResponseEntity<>(emitter, HttpStatus.OK);
    }

    /**
     * 使用SseEmitter实现服务器发送事件(SSE)
     * 每3秒推送自定义事件消息
     */
    @GetMapping("/sse")
    public SseEmitter handleSse() {
        SseEmitter emitter = new SseEmitter();

        // 定时事件推送(3秒间隔)
        scheduler.scheduleAtFixedRate(() -> {
            try {
                // 构建SSE事件:事件名+数据
                SseEmitter.SseEventBuilder event = SseEmitter.event().name("sse").
                    data(String.format("timestamp: %d", System.currentTimeMillis()));
                emitter.send(event);
            } catch (IOException e) {
                emitter.completeWithError(e); // 发生异常时关闭连接
            }
        }, 0, 3, TimeUnit.SECONDS);

        // 15秒超时处理
        // 关闭连接
        emitter.onTimeout(emitter::complete);

        return emitter;
    }

    /**
     * 文件流式传输示例
     * 实现大文件下载(模拟)
     */
    @GetMapping("/stream")
    public ResponseEntity<StreamingResponseBody> handleStream() throws MalformedURLException {
        // 创建远程资源对象(演示用URL)
        Resource resource = new UrlResource("https://blog.youkuaiyun.com/lcj_star/");

        // 流式响应体实现
        StreamingResponseBody stream = outputStream -> {
            try (InputStream inputStream = resource.getInputStream()) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                // 分块传输文件内容
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            } catch (IOException e) {
                log.error("文件读取失败: {}", e.getMessage(), e);
            }
        };

        // 构建响应头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); // 二进制流类型
        headers.setContentDispositionFormData("attachment", resource.getFilename()); // 强制下载

        return ResponseEntity.ok()
            .headers(headers)
            .body(stream);
    }

    /**
     * Callable异步处理示例
     * 模拟耗时操作后返回结果
     */
    @GetMapping("/callAble")
    public Callable<String> testCallAble() {
        return () -> {
            Thread.sleep(4000); // 模拟4秒耗时
            return "hello"; // 返回结果
        };
    }

    /**
     * WebAsyncTask异步处理示例
     * 支持超时和完成回调
     */
    @GetMapping("/webAsyncTask")
    public WebAsyncTask<String> webAsyncTask() {
        // 创建异步任务(超时时间30003ms)
        WebAsyncTask<String> result = new WebAsyncTask<>(30003, () -> {
            return "success"; // 任务主体
        });

        // 超时回调
        result.onTimeout(() -> {
            log.info("timeout callback");
            return "timeout callback";
        });

        // 完成回调
        result.onCompletion(() -> log.info("finish callback"));

        return result;
    }


    /**
     * 延迟结果示例
     * 持有连接等待外部触发结果
     */
    @GetMapping("/deferredResult")
    public DeferredResult<String> testDeferredResult() {
        DeferredResult<String> deferredResult = new DeferredResult<>();
        DEFERRED_RESULT_MAP.put("demo", deferredResult); // 存储实例
        return deferredResult; // 挂起请求
    }

    /**
     * 触发延迟结果
     * 外部调用设置结果
     */
    @GetMapping("/setDeferredResult")
    public String testSetDeferredResult() {
        DeferredResult<String> deferredResult = DEFERRED_RESULT_MAP.get("demo"); // 获取实例
        boolean flag = deferredResult.setResult("DeferredResult hello"); // 设置结果
        if (!flag) {
            log.info("结果已经被处理,此次操作无效");
        }
        return "success";
    }
}

总结

技术适用场景特点
ResponseBodyEmitter持续文本流传输手动控制发送时机
SseEmitter服务端事件推送SSE协议支持
StreamingResponseBody文件流传输适用于大文件下载
Callable简单异步处理自动包装异步执行
WebAsyncTask需回调控制支持超时/完成回调
DeferredResult外部触发可跨请求设置结果
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值