目录
- 简介
- 案例
简介
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);@Nullableprivate 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;}@Nullablepublic Object getResult() {Object resultToCheck = this.result;return resultToCheck != RESULT_NONE ? resultToCheck : null;}@Nullablefinal 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();}}};}@FunctionalInterfacepublic interface DeferredResultHandler {void handleResult(Object result);}
}
案例
下面是DeferredResult
的主要用法和示例说明:
-
异步处理请求:
控制器方法可以返回DeferredResult
,使得该方法可以异步地处理请求。这样,当请求被接收后,控制器方法不会立即返回响应,而是在后台进行处理,最终设置DeferredResult的结果。这允许控制器线程立即释放,从而提高服务器的并发性能。@RestController public class MyController {@Autowiredprivate MyAsyncService asyncService;@GetMapping("/async-operation")public DeferredResult<String> handleAsyncRequest() {DeferredResult<String> deferredResult = new DeferredResult<>();asyncService.performAsyncOperation(result -> {deferredResult.setResult(result);});return deferredResult;} }
-
设置结果:
异步处理完成后,通过设置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;
}
-
错误处理:
可以注册回调函数来处理异常或错误情况。@GetMapping("/async-operation") public DeferredResult<String> handleAsyncRequest() {DeferredResult<String> deferredResult = new DeferredResult<>();deferredResult.onError(e -> {// 处理错误情况});asyncService.performAsyncOperation(result -> {deferredResult.setResult(result);});return deferredResult; }
总的来说,DeferredResult
提供了一种方便的方式来处理异步请求,使得服务器能够高效地处理大量并发请求,并且可以灵活地处理超时和错误情况。