Доступ к прокси-компонентам с заданной областью в потоках - PullRequest
16 голосов
/ 07 октября 2009

У меня есть веб-приложение, работающее на tomcat, где я использую ThreadPool (Java 5 ExecutorService) для параллельного выполнения интенсивных операций ввода-вывода для повышения производительности. Я хотел бы, чтобы некоторые bean-компоненты, используемые в каждом объединенном потоке, находились в области запроса, но потоки в ThreadPool не имеют доступа к контексту Spring и получают ошибку прокси. Любые идеи о том, как сделать контекст Spring доступным для потоков в ThreadPool для устранения ошибок прокси?

Я предполагаю, что должен быть способ зарегистрировать / отменить регистрацию каждого потока в ThreadPool с пружиной для каждой задачи, но у нас не получилось найти способ сделать это.

Спасибо!

Ответы [ 4 ]

47 голосов
/ 03 декабря 2009

Я использую следующий суперкласс для своих задач, которым требуется доступ к области запроса. По сути, вы можете просто расширить его и реализовать свою логику в методе 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();
}
11 голосов
/ 02 декабря 2010

Хотелось бы также, чтобы у меня было 1000 голосов, чтобы отдать принятый в настоящее время ответ. Я был в тупик о том, как сделать это в течение некоторого времени. Основываясь на этом, вот мое решение с использованием интерфейса Callable на случай, если вы захотите использовать некоторые из новых вещей @Async в Spring 3.0.

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 голосов
/ 10 октября 2009

Spring имеет класс ThreadPoolTaskExecutor , который вы можете использовать для управления вашим пулом потоков из Spring. Тем не менее, похоже, что вам придется проделать определенную работу, чтобы сделать контекст Spring доступным для каждого потока.

Я не уверен, будет ли это работать, даже если вы подключите его таким образом. Spring использует токен в локальном потоке для поиска объектов в области запроса (или сеанса), поэтому, если вы пытаетесь получить доступ к компоненту области запроса из другого потока, вероятно, токена там не будет.

0 голосов
/ 07 октября 2009

Не могли бы вы попробовать это наоборот? Используйте контейнер данных, который хранится в области запроса, и передайте его пулу потоков (возможно, поместите его в очередь, чтобы пул потоков мог одновременно принимать по одному контейнеру данных, работать с ним, помечать его как «выполненный» и продолжать со следующим).

...