0

Spring アプリケーションでサーブレット 3.0 の「非同期サポート」を有効にしようとしています。

  • すべてのサーブレットとフィルタのweb.xml (async-supported)true(/async-supported)に追加されました。

  • リクエスト処理コードを次のように書き直しました。

**

request.getAsyncContext().start(new Runnable() {
  @Override
  public void run() {
    handleRequest(servlet, request, response);
  }
});

**

これにより、次の 2 つの問題が発生します。

  1. 非同期コードを実行すると、Spring Security 認証が失われます。

  2. 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>
4

1 に答える 1

1

その非同期スレッドの新しいセッション/エンティティ マネージャーを開く必要があります (セッションはスレッド間で共有できません)。この目的OpenSessionInViewInterceptorのために使用したい場合があります (または、JPA では と呼ばれていると思いOpenEntityManagerInViewInterceptorます) が、そのメソッドを手動で呼び出すか、この目的のために独自のアスペクトを作成してプロキシを使用する必要があります。

于 2012-10-26T14:05:42.947 に答える