web-dev-qa-db-ja.com

実際のWeb要求の外部で要求スコープBeanを使用する

別のスレッドで実行されるSpring Integrationロジックを持つWebアプリケーションがあります。問題は、ある時点でSpring IntegrationロジックがリクエストスコープのBeanを使用しようとすると、次のエラーが発生することです:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.tenantContext': 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.


Caused by: 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.

ContextLoaderListenerを設定しています:

<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

私のScoped Beanにはそのように注釈が付けられています(私のBeanをプロキシすると役立つと聞いたので):

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)  
public class TenantContext  implements Serializable {

私がやっていることは可能ですか?はいの場合、ここで何が欠けていますか?いいえの場合、それを達成する方法に関する他の提案はありますか?

21
Diego Urenia

リクエスト(およびセッション)スコープのBeanは、リクエストが実行されているWebコンテナスレッドでのみ使用できます。

スレッドがSIフローからの非同期応答を待っていると思いますか?

その場合、リクエストスコープのBeanをメッセージにバインドできます(おそらくヘッダー内、またはペイロード内のどこかに)。

10
Gary Russell

Spring 4フレームワークの場合、servletContext.addListener(new RequestContextListener());を追加します。

public class WebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { RootConfiguration.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { WebMvcConfiguration.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    @Override
    protected Filter[] getServletFilters() {
        return new Filter[] { new HiddenHttpMethodFilter() };
    }

    **@Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
        servletContext.addListener(new RequestContextListener());
    }**
}
13
Deepak

プロパティthreadContextInheritableをtrueに設定してRequestContextFilterを使用します。これにより、子スレッドは要求オブジェクト自体を含む親のコンテキストを継承します。また、リクエストオブジェクトはそのリクエストに非常に固有であり、さまざまなリクエスト間で共有できないため、エグゼキュータがプール内のスレッドを再利用しないようにしてください。そのようなエグゼキューターの1つがSimpleAsyncTaskExecutorです。

詳細については、 スコープ 'session'は現在のスレッドに対してアクティブではありません; IllegalStateException:スレッドバインド要求が見つかりません を参照してください。

10
Thilak