小编典典

如何在异步任务执行器中启用请求范围

spring

在我的应用程序中,我有一些异步Web服务。服务器接受请求,返回OK响应,并开始使用AsyncTaskExecutor处理请求。我的问题是如何在此处启用请求范围,因为在此处理中,我需要获取由以下内容注释的类:

@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)

现在我得到异常:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.requestContextImpl': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

因为它在SimpleAsyncTaskExecutor而不是在DispatcherServlet

我的请求异步处理

taskExecutor.execute(new Runnable() {

    @Override
    public void run() {
        asyncRequest(request);
    }
});

taskExecutor在哪里:

<bean id="taskExecutor" class="org.springframework.core.task.SimpleAsyncTaskExecutor" />

阅读 974

收藏
2020-04-11

共1个答案

小编典典

我们遇到了同样的问题-需要使用@Async在后台执行代码,因此它无法使用任何Session-或RequestScope bean。我们通过以下方式解决了它:

  • 创建一个自定义TaskPoolExecutor,用于存储范围内的信息和任务
  • 创建一个特殊的Callable(或Runnable),该信息使用该信息来设置和清除后台线程的上下文
  • 创建替代配置以使用自定义执行程序
    注意:这仅适用于Session和Request作用域的bean,不适用于安全上下文(如Spring Security中一样)。如果您要这样做,则必须使用另一种方法来设置安全上下文。

注意2:为简便起见,仅显示Callable和Submit()实现。您可以对Runnable和execute()执行相同的操作。

这是代码:

Executor:

public class ContextAwarePoolExecutor extends ThreadPoolTaskExecutor {
    @Override
    public <T> Future<T> submit(Callable<T> task) {
        return super.submit(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        return super.submitListenable(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
    }
}

Callable:

public class ContextAwareCallable<T> implements Callable<T> {
    private Callable<T> task;
    private RequestAttributes context;

    public ContextAwareCallable(Callable<T> task, RequestAttributes context) {
        this.task = task;
        this.context = context;
    }

    @Override
    public T call() throws Exception {
        if (context != null) {
            RequestContextHolder.setRequestAttributes(context);
        }

        try {
            return task.call();
        } finally {
            RequestContextHolder.resetRequestAttributes();
        }
    }
}

Configuration:

@Configuration
public class ExecutorConfig extends AsyncConfigurerSupport {
    @Override
    @Bean
    public Executor getAsyncExecutor() {
        return new ContextAwarePoolExecutor();
    }
}
2020-04-11