`DeferredResult`用法简单介绍

简介: `DeferredResult`用法简单介绍

简介

DeferredResult是Spring Framework中用于处理异步请求的一个类,通常与Spring MVC的Controller一起使用。它允许控制器在请求处理完成后,异步地生成响应,而不必阻塞线程等待结果。这对于处理需要耗时的操作或长时间等待外部资源响应的请求非常有用。

public class DeferredResult<T> {
    private static final Object RESULT_NONE = new Object();
    private static final Log logger = LogFactory.getLog(DeferredResult.class);
    @Nullable
    private final Long timeoutValue;
    private final Supplier<?> timeoutResult;
    private Runnable timeoutCallback;
    private Consumer<Throwable> errorCallback;
    private Runnable completionCallback;
    private DeferredResultHandler resultHandler;
    private volatile Object result;
    private volatile boolean expired;
    public DeferredResult() {
        this((Long)null, (Supplier)(() -> {
            return RESULT_NONE;
        }));
    }
    public DeferredResult(Long timeoutValue) {
        this(timeoutValue, () -> {
            return RESULT_NONE;
        });
    }
    public DeferredResult(@Nullable Long timeoutValue, Object timeoutResult) {
        this.result = RESULT_NONE;
        this.timeoutValue = timeoutValue;
        this.timeoutResult = () -> {
            return timeoutResult;
        };
    }
    public DeferredResult(@Nullable Long timeoutValue, Supplier<?> timeoutResult) {
        this.result = RESULT_NONE;
        this.timeoutValue = timeoutValue;
        this.timeoutResult = timeoutResult;
    }
    public final boolean isSetOrExpired() {
        return this.result != RESULT_NONE || this.expired;
    }
    public boolean hasResult() {
        return this.result != RESULT_NONE;
    }
    @Nullable
    public Object getResult() {
        Object resultToCheck = this.result;
        return resultToCheck != RESULT_NONE ? resultToCheck : null;
    }
    @Nullable
    final Long getTimeoutValue() {
        return this.timeoutValue;
    }
    public void onTimeout(Runnable callback) {
        this.timeoutCallback = callback;
    }
    public void onError(Consumer<Throwable> callback) {
        this.errorCallback = callback;
    }
    public void onCompletion(Runnable callback) {
        this.completionCallback = callback;
    }
    public final void setResultHandler(DeferredResultHandler resultHandler) {
        Assert.notNull(resultHandler, "DeferredResultHandler is required");
        if (!this.expired) {
            Object resultToHandle;
            synchronized(this) {
                if (this.expired) {
                    return;
                }
                resultToHandle = this.result;
                if (resultToHandle == RESULT_NONE) {
                    this.resultHandler = resultHandler;
                    return;
                }
            }
            try {
                resultHandler.handleResult(resultToHandle);
            } catch (Throwable var5) {
                logger.debug("Failed to process async result", var5);
            }
        }
    }
    public boolean setResult(T result) {
        return this.setResultInternal(result);
    }
    private boolean setResultInternal(Object result) {
        if (this.isSetOrExpired()) {
            return false;
        } else {
            DeferredResultHandler resultHandlerToUse;
            synchronized(this) {
                if (this.isSetOrExpired()) {
                    return false;
                }
                this.result = result;
                resultHandlerToUse = this.resultHandler;
                if (resultHandlerToUse == null) {
                    return true;
                }
                this.resultHandler = null;
            }
            resultHandlerToUse.handleResult(result);
            return true;
        }
    }
    public boolean setErrorResult(Object result) {
        return this.setResultInternal(result);
    }
    final DeferredResultProcessingInterceptor getInterceptor() {
        return new DeferredResultProcessingInterceptor() {
            public <S> boolean handleTimeout(NativeWebRequest request, DeferredResult<S> deferredResult) {
                boolean continueProcessing = true;
                boolean var12 = false;
                try {
                    var12 = true;
                    if (DeferredResult.this.timeoutCallback != null) {
                        DeferredResult.this.timeoutCallback.run();
                        var12 = false;
                    } else {
                        var12 = false;
                    }
                } finally {
                    if (var12) {
                        Object value = DeferredResult.this.timeoutResult.get();
                        if (value != DeferredResult.RESULT_NONE) {
                            continueProcessing = false;
                            try {
                                DeferredResult.this.setResultInternal(value);
                            } catch (Throwable var13) {
                                DeferredResult.logger.debug("Failed to handle timeout result", var13);
                            }
                        }
                    }
                }
                Object valuex = DeferredResult.this.timeoutResult.get();
                if (valuex != DeferredResult.RESULT_NONE) {
                    continueProcessing = false;
                    try {
                        DeferredResult.this.setResultInternal(valuex);
                    } catch (Throwable var14) {
                        DeferredResult.logger.debug("Failed to handle timeout result", var14);
                    }
                }
                return continueProcessing;
            }
            public <S> boolean handleError(NativeWebRequest request, DeferredResult<S> deferredResult, Throwable t) {
                try {
                    if (DeferredResult.this.errorCallback != null) {
                        DeferredResult.this.errorCallback.accept(t);
                    }
                } finally {
                    try {
                        DeferredResult.this.setResultInternal(t);
                    } catch (Throwable var10) {
                        DeferredResult.logger.debug("Failed to handle error result", var10);
                    }
                }
                return false;
            }
            public <S> void afterCompletion(NativeWebRequest request, DeferredResult<S> deferredResult) {
                DeferredResult.this.expired = true;
                if (DeferredResult.this.completionCallback != null) {
                    DeferredResult.this.completionCallback.run();
                }
            }
        };
    }
    @FunctionalInterface
    public interface DeferredResultHandler {
        void handleResult(Object result);
    }
}

案例

下面是DeferredResult的主要用法和示例说明:

  1. 异步处理请求:
    控制器方法可以返回DeferredResult,使得该方法可以异步地处理请求。这样,当请求被接收后,控制器方法不会立即返回响应,而是在后台进行处理,最终设置DeferredResult的结果。这允许控制器线程立即释放,从而提高服务器的并发性能。
@RestController
public class MyController {
    @Autowired
    private MyAsyncService asyncService;
    @GetMapping("/async-operation")
    public DeferredResult<String> handleAsyncRequest() {
        DeferredResult<String> deferredResult = new DeferredResult<>();
        asyncService.performAsyncOperation(result -> {
            deferredResult.setResult(result);
        });
        return deferredResult;
    }
}
  1. 设置结果:
    异步处理完成后,通过设置DeferredResult的结果来响应客户端请求。
public class MyAsyncService {
    public void performAsyncOperation(Consumer<String> callback) {
        // 异步处理操作
        String result = ...; // 执行异步操作获取结果
        callback.accept(result);
    }
}
@FunctionalInterface
public interface Consumer<T> {
    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
    /**
     * Returns a composed {@code Consumer} that performs, in sequence, this
     * operation followed by the {@code after} operation. If performing either
     * operation throws an exception, it is relayed to the caller of the
     * composed operation.  If performing this operation throws an exception,
     * the {@code after} operation will not be performed.
     *
     * @param after the operation to perform after this operation
     * @return a composed {@code Consumer} that performs in sequence this
     * operation followed by the {@code after} operation
     * @throws NullPointerException if {@code after} is null
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

在这个示例中,Consumer<String>是一个函数式接口,它定义了一个接收一个参数并且不返回任何结果的操作。具体来说,Consumer<String>表示接受一个String类型的参数,并对该参数进行处理,但不返回任何结果。

在MyAsyncService类中的performAsyncOperation方法中,它接受一个Consumer<String>类型的参数callback。在异步处理操作完成后,会调用callback.accept(result)方法,将异步操作的结果result传递给这个callback。

这样做的好处是,MyAsyncService类不需要知道具体的异步操作是如何实现的,它只需要在异步操作完成后将结果传递给callback,由调用方来定义具体的处理逻辑。这种方式使得代码更加灵活和可扩展,符合面向接口编程的思想。

3. 超时处理:

可以设置DeferredResult的超时时间,如果在规定的时间内未设置结果,可以触发超时处理。

@GetMapping("/async-operation")
public DeferredResult<String> handleAsyncRequest() {
    DeferredResult<String> deferredResult = new DeferredResult<>(5000L); // 设置5秒超时
    asyncService.performAsyncOperation(result -> {
        deferredResult.setResult(result);
    });
    return deferredResult;
}
  1. 错误处理:
    可以注册回调函数来处理异常或错误情况。
@GetMapping("/async-operation")
public DeferredResult<String> handleAsyncRequest() {
    DeferredResult<String> deferredResult = new DeferredResult<>();
    deferredResult.onError(e -> {
        // 处理错误情况
    });
    asyncService.performAsyncOperation(result -> {
        deferredResult.setResult(result);
    });
    return deferredResult;
}

总的来说,DeferredResult提供了一种方便的方式来处理异步请求,使得服务器能够高效地处理大量并发请求,并且可以灵活地处理超时和错误情况。

相关文章
|
7月前
|
存储 JavaScript 算法
TS泛型类型
TS泛型类型
66 0
|
JavaScript
对TS里接口、extends和类的理解
对TS里接口、extends和类的理解
104 1
|
Java
ts装饰器(注解)
ts装饰器(注解)
101 0
|
JavaScript
ts - 重载
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。
|
JavaScript 前端开发 IDE
什么是ts,作用是什么
什么是ts,作用是什么
1364 0
|
SQL XML Java
Mybatis开发要点-resultType和resultMap的区别?
Mybatis开发要点-resultType和resultMap的区别?
141 0
ts重点学习77-泛型接口
ts重点学习77-泛型接口
72 0
ts重点学习77-泛型接口
ts重点学习78-泛型接口
ts重点学习78-泛型接口
89 0
ts重点学习78-泛型接口
|
JSON JavaScript 数据格式
res 对象的常见方法|学习笔记
快速学习 res 对象的常见方法
res 对象的常见方法|学习笔记
|
JavaScript 开发者
res.setHeader 方法和 res.writeHead 方法|学习笔记
快速学习 res.setHeader 方法和 res.writeHead 方法