2009-10-06 3 views
15

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

Я предполагаю, что должен быть способ зарегистрировать/отменить регистрацию каждой нити в 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

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

0

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

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

+0

Это всего лишь способ создать исполнителя. настоящая проблема заключается в том, что ', но потоки в ThreadPool не имеют доступа к весеннему контексту и получают прокси-отказ. '. – msangel

11

Я также хотел, чтобы у меня было 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

gr8 !! Я искал это :) – hop

+0

ОК, у меня есть метод с аннотацией '@ Async'. это returnig 'Future ' результат. Я уверен, что внутри класса, созданного прокси, есть «ThreadExecutor» и «Callabbe », но как заставить его использовать такой тип Callable? Как временное решение, я просто передаю ссылку на контекст приложения в метод, он работает для меня, но он не выглядит хорошо. – msangel

+0

Я думаю, что этот код может быть проблемой. RequestContextHolder.getRequestAttributes() возвращает тот же экземпляр, который используется в текущем запросе, а не в копии. Таким образом, вы можете получить доступ к объекту ServletRequestAttributes за пределами диапазона запроса сервлета ... –

Смежные вопросы