Spring アプリケーションでサーブレット 3.0 の「非同期サポート」を有効にしようとしています。
すべてのサーブレットとフィルタのweb.xml (async-supported)true(/async-supported)に追加されました。
リクエスト処理コードを次のように書き直しました。
**
request.getAsyncContext().start(new Runnable() {
@Override
public void run() {
handleRequest(servlet, request, response);
}
});
**
これにより、次の 2 つの問題が発生します。
非同期コードを実行すると、Spring Security 認証が失われます。
EntityManager/session/... ももうありません。
もちろん、どちらの問題も、Runnable を作成したスレッドと同じスレッドでハンドラ コードが実行されていないことが原因です。理想的には、ワーカー スレッドは呼び出しスレッドから Spring コンテキストを「継承」する必要があります。
構築時に認証を保存し、実行時に設定することで、Spring Security の問題を回避できました。
private final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
try {
SecurityContextHolder.clearContext();
SecurityContextHolder.getContext().setAuthentication(authentication);
..run code here..
} finally {
SecurityContextHolder.clearContext();
}
ただし、2番目の問題については、セッションを実行中のスレッドに「転送」する方法がわかりません。サーブレット 2.x では、OpenEntityManagerInViewFilterを使用してセッションをスレッドに固定していました。
<filter>
<filter-name>openEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>entityManagerFactoryBeanName</param-name>
<param-value>entityManagerFactory</param-value>
</init-param>
</filter>
しかし、もちろん、これはもはや意味がありません。それが固執するスレッドは、リクエストを実行したスレッドと同じではないからです。
Spring 3.1 と 3.2 のさまざまなバージョンを試しました。しかし、効果はありません。
これを回避する方法を知っている人はいますか? できればハッキングで。:-)
私のweb.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>Foo</servlet-name>
<servlet-class>com.foo.Main</servlet-class>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>Foo</servlet-name>
<url-pattern>/restricted/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>openEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>entityManagerFactoryBeanName</param-name>
<param-value>entityManagerFactory</param-value>
</init-param>
</filter>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.bar.ServletInit</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.foo.SpringCtxInitializer</param-value>
</context-param>
<filter-mapping>
<filter-name>openEntityManagerInViewFilter</filter-name>
<url-pattern>/restricted/*</url-pattern>
</filter-mapping>
</web-app>