2009-10-06 16 views
15

パフォーマンスを向上させるためにIO集中型操作を並列実行するためにThreadPool(Java 5 ExecutorService)を使用しているTomcatでWebアプリケーションを実行しています。それぞれのプールされたスレッド内で使用されているBeanのいくつかを要求スコープに入れたいのですが、ThreadPoolのスレッドはSpringコンテキストにアクセスできず、プロキシのエラーが発生します。 ThreadPoolのスレッドがSpringのコンテキストを利用できるようにして、プロキシの失敗を解決する方法に関するアイデアはありますか?スレッド内スコープ付きプロキシBeanへのアクセス

私は、ThreadPoolの各スレッドを各タスクの春に登録/登録解除する方法があるはずですが、これを行う方法が見つからなかったと思います。

ありがとうございます!

答えて

45

リクエストスコープにアクセスする必要があるタスクに、次のスーパークラスを使用しています。基本的には、それを拡張してonRun()メソッドでロジックを実装することができます。

import org.springframework.web.context.request.RequestAttributes; 
import org.springframework.web.context.request.RequestContextHolder; 

/** 
* @author Eugene Kuleshov 
*/ 
public abstract class RequestAwareRunnable implements Runnable { 
    private final RequestAttributes requestAttributes; 
    private Thread thread; 

    public RequestAwareRunnable() { 
    this.requestAttributes = RequestContextHolder.getRequestAttributes(); 
    this.thread = Thread.currentThread(); 
    } 

    public void run() { 
    try { 
     RequestContextHolder.setRequestAttributes(requestAttributes); 
     onRun(); 
    } finally { 
     if (Thread.currentThread() != thread) { 
     RequestContextHolder.resetRequestAttributes(); 
     } 
     thread = null; 
    } 
    } 

    protected abstract void onRun(); 
} 
+0

ユージンの助けをありがとう。とても有難い! – Perulish8

+3

うわー。私はこれをさらに10票のようにバンプすることができたらいいと思う。助けてくれてありがとう。 – Cameron

+2

このメソッドにはデッドロックがあるようです。http://stackoverflow.com/q/15768556/438742 – kan

0

他の方法で試してもらえますか?要求スコープに格納されているデータコンテナを使用して、スレッドプールに渡します(スレッドプールは一度に1つのデータコンテナを取り、作業し、完了したとしてマークして処理を継続できるようにします)次のものと一緒に)。

0

Springには、Springからスレッドプールを管理するために使用できるThreadPoolTaskExecutorクラスがあります。しかし、各スレッドがSpringコンテキストを利用できるようにするには、いくつかの作業が必要になるようです。

この方法でワイヤリングしても機能するかどうかはわかりません。 Springは要求(またはセッション)スコープ内のオブジェクトを見つけるためにスレッドローカルのトークンを使います。したがって、別のスレッドから要求スコープBeanにアクセスしようとすると、トークンはそこに存在しない可能性があります。

+0

これはエグゼキュータを作成する単なる方法です。ここでの本当の問題は 'しかし、ThreadPoolのスレッドはSpringのコンテキストにアクセスすることができず、プロキシの失敗を起こします。 ' – msangel

11

また、私は現在受け入れられている回答に1000票を与えたいと思います。私はしばらくの間、これをどうやって行うのか困惑していました。それに基づいて、Spring 3.0で新しい@Asyncのいくつかを使いたい場合にCallableインターフェイスを使用した私の解決策がここにあります。

public abstract class RequestContextAwareCallable<V> implements Callable<V> { 

    private final RequestAttributes requestAttributes; 
    private Thread thread; 

    public RequestContextAwareCallable() { 
     this.requestAttributes = RequestContextHolder.getRequestAttributes(); 
     this.thread = Thread.currentThread(); 
    } 

    public V call() throws Exception { 
     try { 
      RequestContextHolder.setRequestAttributes(requestAttributes); 
      return onCall(); 
     } finally { 
      if (Thread.currentThread() != thread) { 
       RequestContextHolder.resetRequestAttributes(); 
      } 
      thread = null; 
     } 
    } 

    public abstract V onCall() throws Exception; 
} 
+0

gr8 !!私はこれを探していた: – hop

+0

大丈夫、 '@ Async'アノテーションを持つメソッドがある。 returnig 'Future '結果です。私はプロキシ生成クラスの中に 'ThreadExecutor'と' Callabbe 'がありますが、そのような種類のCa​​llableを強制する方法はありますか? 一時的な解決策として、私はちょうどメソッドへのアプリケーションのコンテキスト参照を渡す、それは私のために働くが、それは良い見ていない。 – msangel

+0

このコードに問題があると思います。 RequestContextHolder.getRequestAttributes()は、コピーではなく、現在のリクエストで使用されているものと同じインスタンスを返します。したがって、サーブレットリクエストの範囲外でServletRequestAttributesオブジェクトにアクセスしている可能性があります... –

関連する問題