2011-10-03 8 views
8

Scenariusz: Mamy aplikację internetową zarządzaną przez Spring, która działa w sieci Websphere. (Wiosna 3.0.x, WAS 7) Aplikacja webowa wykorzystuje menedżera pracy Websphere za pośrednictwem Spring WorkManagerTaskExecutor (skonfigurowany z pulą wątków o wielkości 10) w celu wykonywania intensywnych obliczeń operacji odczytu bazy danych. Zasadniczo pojawia się żądanie wygenerowania, powiedzmy, 10 różnych dokumentów. Do generowania dokumentów potrzebne są tylko odczyty db do zbierania/przetwarzania danych. Zasadniczo odradzamy 10 wątków, aby przetworzyć 10 dokumentów, a na końcu zebrać 10 dokumentów zwróconych od 10 pracowników i połączyć je i odpisać jedną dużą odpowiedź dla klienta. Zidentyfikowaliśmy, że podczas gdy 10 wątków zbiera/przetwarza dane, powstaje wiązka podobnych wywołań db. Więc stworzyliśmy Aspekt wokół najczęściej wykonywanych metod db do buforowania odpowiedzi. Aspekt jest skonfigurowany jako singleton, a pamięć podręczna, której używa aspekt, jest automatycznie przekształcana w aspekt z zakresem ustawionym na request-scope, tak aby każde żądanie miało własną pamięć podręczną.Uzyskiwanie dostępu do komponentu bean o żądanej liczbie zapytań w wielowątkowej aplikacji internetowej

Problem: Problem z tym podejściem polega na tym, że gdy wątki wykonują swoje wywołania db, a Aspekt jest wtrącany, otrzymujemy wyjątek java.lang.IllegalStateException: No thread-bound request found. Rozumiem, że jest to całkowicie prawidłowe, ponieważ wątki są wykonywane poza kontekstem żądania.

Czy istnieje sposób na obejście tego problemu? Czy możliwe jest zastosowanie aspektu z pamięcią podręczną o zakresie zapytań do metod wywoływanych przez te wątki?

Odpowiedz

5

Nie sądzę, możesz zrobić to bezpośrednio. Nawet gdybyś mógł, byłoby to trochę brzydkie. Można jednak wygenerować unikalny identyfikator żądania (lub nawet - użyć identyfikatora sesji, ale ostrożnie z wieloma zakładkami) i przekazać go do każdego wątku przetwarzania. Następnie aspekt może użyć tego identyfikatora jako klucza do pamięci podręcznej. Sama pamięć podręczna również będzie pojedyncza, ale będzie Map<String, X>, gdzie String to identyfikator, a X to wynik z pamięci podręcznej.

Aby ułatwić obsługę, można stosować metody @Async (zamiast ręcznego odradzania wątków), a każda metoda @Async może przekazać identyfikator pamięci podręcznej jako pierwszy parametr.

(Oczywiście, wasze metody asynchroniczne powinien powrócić Future<Result> tak że można zebrać swoje wyniki w wątku życzenie)

+0

myślałem o podejściu, ale jedna wada, że ​​uważam, że zmusi mnie do przejść unikalny identyfikator żądania poniżej wszystkich wywołań metod (podczas wykonywania wątku), które chciałbym buforować. Czy pamięć podręczna po pewnym czasie nie stałaby się naprawdę duża? Co zmusiłoby mnie do okresowego zarządzania. Może czegoś tu brakuje. – r4j1v

+0

Być może istnieje "kontekst wykonania wątku", który mogę wykorzystać do przechowywania mojego unikalnego identyfikatora żądania i pobrania go w aspekcie bez konieczności przekazywania go samemu? – r4j1v

+5

Udało mi się ominąć ten problem. Zacząłem używać 'SimpleAsyncTaskExecutor' zamiast' WorkManagerTaskExecutor'. Korzyścią jest to, że 'SimpleAsyncTaskExecutor' nigdy nie użyje ponownie wątków. To tylko połowa rozwiązania. Drugą połową rozwiązania jest użycie 'RequestContextFilter' zamiast' RequestContextListener'. 'RequestContextFilter' ma metodę' setThreadContextInheritable() ', która zasadniczo umożliwia wątkom potomnym dziedziczenie kontekstu nadrzędnego. – r4j1v

Powiązane problemy