16

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

ThreadPoolの各スレッドを各タスクのスプリングで登録/登録解除する方法があるはずだと思いますが、これを行う方法を見つけることができませんでした。

ありがとう!

4

4 に答える 4

48

リクエストスコープにアクセスする必要があるタスクには、次のスーパークラスを使用しています。基本的には、それを拡張して、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();
}
于 2009-12-03T01:26:32.977 に答える
12

また、現在受け入れられている回答に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;
}
于 2010-12-02T00:50:23.517 に答える
0

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

このように配線してもうまくいくかどうかはわかりませんが。Springはスレッドローカルのトークンを使用してリクエスト(またはセッション)スコープ内のオブジェクトを検索するため、別のスレッドからリクエストスコープBeanにアクセスしようとすると、トークンが存在しない可能性があります。

于 2009-10-10T13:34:08.093 に答える
0

逆に試していただけませんか?リクエストスコープに格納されているデータコンテナを使用して、スレッドプールに渡します(おそらく、スレッドプールが一度に1つのデータコンテナを取得して処理し、「完了」としてマークして続行できるように、キューに入れます)。次のものと)。

于 2009-10-07T06:55:37.360 に答える