spring 升级到JDK 17和Sping Boot 3后,异步仅接受Future和void作为返回类型

olmpazwi  于 2022-12-17  发布在  Spring
关注(0)|答案(1)|浏览(1378)

我刚刚将我的项目从JDK 11更新到JDK 17,并从Sping Boot 2.7.5更新到3.0.0。
当我尝试运行异步方法时,它抛出如下异常

com.app.svc.exception.ControllerException: Invalid return type for async method (only Future and void supported): class com.app.svc.model.ResponseModel

代码如下所示:

@Async("threadPoolTaskExecutor")
@Override
public ResponseModel startRequest(RequestModel request, Logger logger) throws Exception { ... }

它在我升级之前就可以工作了,所以我认为不返回Futurevoid是可以接受的。在JDK 17或Sping Boot 3.0.0中有改变吗?或者我做错了什么?
感谢任何帮助,谢谢!

ghg1uchk

ghg1uchk1#

该错误已添加到Spring Framework 6(使用this issue)中。
简言之,@Async只支持voidFuture返回类型,如果你返回其他类型,它会返回null而不是实际值(如果异步工作正常),因为它需要从调用中立即返回,这基本上模拟了void
虽然支持的返回类型从@Async开始就有记录(参见@Async第一版中的the javadoc),但在使用异步的方面从未真正实施过。
最后一点已经在Spring Framework 6(带有this issue)中得到了解决,以防止像您遇到的和前面提到的问题中记录的那样的意外。
Spring框架3的源代码(可在此处找到)

public Object invoke(final MethodInvocation invocation) throws Throwable {

    Future result = this.asyncExecutor.submit(new Callable<Object>() {
        public Object call() throws Exception {
            try {
                Object result = invocation.proceed();
                if (result instanceof Future) {
                    return ((Future) result).get();
                }
            }
            catch (Throwable ex) {
                ReflectionUtils.rethrowException(ex);
            }
            return null;
        }
    });
    if (Future.class.isAssignableFrom(invocation.getMethod().getReturnType())) {
        return result;
    }
    else {
        return null;
    }
}

你可以看到在原始代码中,它只检查返回类型是否为Future,如果是,它将被返回,否则它将返回null

@Nullable
@SuppressWarnings("deprecation")
protected Object doSubmit(Callable<Object> task, AsyncTaskExecutor executor, Class<?> returnType) {
    if (CompletableFuture.class.isAssignableFrom(returnType)) {
        return executor.submitCompletable(task);
    }
    else if (org.springframework.util.concurrent.ListenableFuture.class.isAssignableFrom(returnType)) {
        return ((org.springframework.core.task.AsyncListenableTaskExecutor) executor).submitListenable(task);
    }
    else if (Future.class.isAssignableFrom(returnType)) {
        return executor.submit(task);
    }
    else if (void.class == returnType) {
        executor.submit(task);
        return null;
    }
    else {
        throw new IllegalArgumentException(
                "Invalid return type for async method (only Future and void supported): " + returnType);
    }
}

在最新的SpringFramework6中,代码已经被修改,现在显式地检查所有支持的返回类型。如果没有发现任何返回类型,则抛出异常。(代码在这里)。

相关问题