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

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

问题描述

在我的应用程序中,我有一些异步Web服务。服务器接受请求,返回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.

Note2 :为简洁起见,仅限于显示了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天全站免登陆