Доступ к bean-объектам в области запросов в многопоточном веб-приложении

Сценарий: у нас есть управляемое Spring веб-приложение, которое работает внутри Websphere. (Spring 3.0.x, WAS 7) Веб-приложение использует менеджер работы Websphere через Spring. WorkManagerTaskExecutor (настроен с размером пула потоков 10) для выполнения вычислительных операций интенсивного чтения БД. Таким образом, в основном, приходит запрос на генерацию, скажем, 10 различных документов. Для генерации документов требуется только чтение базы данных для сбора / обработки данных. Таким образом, мы в основном создаем 10 потоков для обработки 10 документов и в конце собираем 10 документов, возвращенных 10 рабочими, объединяем их и записываем один большой ответ клиенту. Мы определили, что в то время как 10 потоков собирают / обрабатывают данные, выполняется множество похожих вызовов в БД. Итак, мы пришли к тому, чтобы создать Аспект вокруг наиболее исполняемых методов БД для кеширования ответа. Аспект настроен как одноэлементный, и кэш, который использует аспект, автоматически подключается к аспекту с областью действия, установленной на область запроса, так что каждый запрос имеет свой собственный кэш.

Проблема: Теперь проблема с этим подходом состоит в том, что когда потоки выполняют свои вызовы БД, а Аспект - это interjects, мы получаем java.lang.IllegalStateException: No thread-bound request found исключение. То, что я понимаю, полностью верно, поскольку потоки выполняются вне контекста запроса.

Есть ли способ обойти эту проблему? Можно ли применить аспект с кэшем области запроса к методам, вызываемым этими потоками?

1 ответ

Решение

Я не думаю, что вы можете сделать это напрямую. Даже если бы ты мог, это было бы немного некрасиво. Однако вы можете сгенерировать уникальный идентификатор запроса (или даже использовать идентификатор сеанса, но осторожно с несколькими вкладками) и передать его каждому потоку обработки. Тогда аспект может использовать этот идентификатор в качестве ключа к кешу. Сам кеш тоже будет одноэлементным, но там будет Map<String, X>, где String это идентификатор, а X - ваш кешированный результат.

Чтобы сделать вещи проще, вы можете иметь @Async методы (а не порождения потоков вручную), и каждый @Async Метод может иметь идентификатор кэша, передаваемый в качестве первого параметра.

(Конечно, ваши асинхронные методы должны возвращать Future<Result> так что вы можете собрать свои результаты в ветке запроса)

Другие вопросы по тегам