如何在异步任务执行器中启用请求范围 [英] How to enable request scope in async task executor

查看:40
本文介绍了如何在异步任务执行器中启用请求范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In my app I have some async web services. Server accept request, return OK response and start processing request with AsyncTaskExecutor. My question is how to enable request scope here because in this processing I need to get class which is annotated by:

@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

because it runs in SimpleAsyncTaskExecutor and not in DispatcherServlet

我对请求的异步处理

taskExecutor.execute(new Runnable() {

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

taskExecutor 在哪里:

where taskExecutor is:

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

推荐答案

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

We ran into the same problem - needed to execute code in the background using @Async, so it was unable to use any Session- or RequestScope beans. We solved it the following way:

  • 创建一个自定义 TaskPoolExecutor,用于存储任务的范围信息
  • 创建一个特殊的 Callable(或 Runnable),它使用这些信息来设置和清除后台线程的上下文
  • 创建覆盖配置以使用自定义执行器

注意:这仅适用于会话和请求范围的 bean,而不适用于安全上下文(如在 Spring Security 中).如果这是您所追求的,则必须使用另一种方法来设置安全上下文.

Note: this will only work for Session and Request scoped beans, and not for security context (as in Spring Security). You'd have to use another method to set the security context if that is what you're after.

注意 2:为简洁起见,仅展示了 Callable 和 submit() 实现.您可以对 Runnable 和 execute() 执行相同操作.

Note2: For brevity, only shown the Callable and submit() implementation. You can do the same for the Runnable and execute().

代码如下:

执行者:

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()));
    }
}

可调用:

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
public class ExecutorConfig extends AsyncConfigurerSupport {
    @Override
    @Bean
    public Executor getAsyncExecutor() {
        return new ContextAwarePoolExecutor();
    }
}

这篇关于如何在异步任务执行器中启用请求范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆