Zakres 'session' nie jest aktywny dla bieżącego wątku; IllegalStateException: nie znaleziono żądania związanego z wątkiem
Mam kontroler, który chciałbym być unikalny na sesję. Zgodnie z dokumentacją spring istnieją dwa szczegóły realizacji:
1. Wstępna konfiguracja www
[10]} Aby Obsługiwać zakres fasoli na poziomie request, session I global session (Web-scoped beans), wymagana jest niewielka początkowa konfiguracja przed zdefiniowaniem fasoli.
Dodałem do mojego web.xml
Jak pokazano w dokumentacja:
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
2. Scoped beans as dependencies
Jeśli chcesz wstrzyknąć (na przykład) żądanie HTTP scoped bean do innej bean, musisz wprowadzić proxy AOP zamiast scoped bean.
Przypisałem fasolkę @Scope
podając proxyMode
Jak pokazano poniżej:
@Controller
@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class ReportBuilder implements Serializable {
...
...
}
Problem
Pomimo powyższej konfiguracji dostaję następujący wyjątek:
Org.springframework.fasola.fabryka.BeanCreationException: błąd podczas tworzenia bean o nazwie ' scopedTarget.reportBuilder': Scope 'session' nie jest aktywna dla bieżącego wątku; rozważ zdefiniowanie scoped proxy dla tej fasoli, jeśli zamierzasz odwoływać się do niej z singletonu; zagnieżdżonym wyjątkiem jest java.lang.IllegalStateException: nie znaleziono żądania związanego z wątkiem: czy odnosisz się do atrybutów żądania poza rzeczywistym żądaniem internetowym, czy też przetwarzasz żądanie poza pierwotnie otrzymującym wątek? Jeśli faktycznie działasz w żądaniu internetowym i nadal otrzymujesz tę wiadomość, Twój kod prawdopodobnie działa poza DispatcherServlet/DispatcherPortlet: w tym przypadku użyj RequestContextListener lub RequestContextFilter, aby ujawnić bieżące żądanie.
Update 1
Poniżej znajduje się mój skan komponentów. Mam w web.xml
:
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>org.example.AppConfig</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Oraz w AppConfig.java
:
@Configuration
@EnableAsync
@EnableCaching
@ComponentScan("org.example")
@ImportResource("classpath:applicationContext.xml")
public class AppConfig implements AsyncConfigurer {
...
...
}
Update 2
I ' ve created a powtarzalny przypadek testowy. Jest to znacznie mniejszy projekt, więc są różnice, ale zdarza się ten sam błąd. Jest sporo plików, więc wrzuciłem je jako tar.gz
do megafileupload .
9 answers
Problem nie leży w Twoich adnotacjach wiosennych, ale w Twoim wzorze projektowym. Mieszasz ze sobą różne zakresy i wątki:
- singleton
- sesja (lub żądanie)
- thread pool of jobs
Singleton jest dostępny wszędzie, jest ok. Zakres sesji/żądania nie jest jednak dostępny poza wątkiem dołączonym do żądania.
Asynchroniczne zadanie może być uruchomione nawet wtedy, gdy żądanie lub sesja już nie istnieje, więc nie jest możliwe użycie request / session dependent bean. Nie ma również sposobu, aby dowiedzieć się, czy Twoje zadanie jest uruchomione w osobnym wątku, który wątek jest żądaniem inicjatora (oznacza to, że AOP:proxy nie jest pomocny w tym przypadku).
Myślę, że Twój kod wygląda tak, że chcesz zawrzeć umowę pomiędzy ReportController, ReportBuilder, UselessTask i ReportPage. Czy istnieje sposób na użycie prostej klasy (POJO) do przechowywania danych z UselessTask i odczytywania ich w ReportController lub ReportPage i do nie używaj już ReportBuilder ?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-11 17:42:08
Odpowiadam na własne pytanie, ponieważ zapewnia lepszy przegląd przyczyny i możliwych rozwiązań. Przyznałem bonus @Martin, bo wskazał przyczynę.
Cause
Zgodnie z sugestią @Martin przyczyną jest użycie wielu wątków. Obiekt request nie jest dostępny w tych wątkach, jak wspomniano w Spring Guide:
DispatcherServlet
,RequestContextListener
iRequestContextFilter
wszystkie robią dokładnie to samo, mianowicie wiążą żądanie HTTP zgłoś sprzeciw wobec wątku obsługującego to żądanie. To sprawia, że ziarna, które są request - I session-scoped dostępne dalej w łańcuchu połączeń.
Rozwiązanie 1
Możliwe jest udostępnienie obiektu request innym wątkom, ale nakłada to na system kilka ograniczeń, które mogą nie być wykonalne we wszystkich projektach. Mam To rozwiązanie z dostęp do request scoped beans w wielowątkowej aplikacji internetowej :
I udało się obejść ten problem. Zacząłem używać
SimpleAsyncTaskExecutor
zamiastWorkManagerTaskExecutor
/ThreadPoolExecutorFactoryBean
. Zaletą jest to, żeSimpleAsyncTaskExecutor
nigdy nie będzie ponownie używać wątków. To tylko połowa rozwiązania. Druga połowa roztworu to użycieRequestContextFilter
zamiastRequestContextListener
.RequestContextFilter
(jak równieżDispatcherServlet
) posiada właściwośćthreadContextInheritable
, która zasadniczo pozwala wątkom potomnym dziedziczyć kontekst nadrzędny.
Rozwiązanie 2
Jedyną inną opcją jest użycie zakresu sesji w wątku żądania. W moim przypadku nie było to możliwe, ponieważ:
- metoda kontrolera jest opatrzona adnotacją
@Async
; - metoda kontrolera uruchamia zadanie wsadowe, które wykorzystuje wątki do równoległych kroków zadania.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:20
Jeśli ktoś jeszcze utknął w tym samym punkcie, podążanie za nim rozwiązało mój problem.
W sieci.xml
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
W komponencie Sesji
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
W pom.xml
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-12 17:21:44
As per documentation :
Jeśli uzyskujesz dostęp do scoped beans w Spring Web MVC, tzn. w żądaniu, które jest przetwarzane przez Spring DispatcherServlet lub DispatcherPortlet, wtedy nie jest wymagana żadna specjalna konfiguracja: DispatcherServlet i DispatcherPortlet już ujawniają wszystkie odpowiednie stany.
Jeśli uruchamiasz się poza Spring MVC (Nie przetwarzane przez DispatchServlet), musisz użyć RequestContextListener
, a nie tylko ContextLoaderListener
.
Dodaj w sieci.xml
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
Które zapewnią sesję do wiosny w celu utrzymania fasoli w tym zakresie
Update :
Jak na inne odpowiedzi, @Controller
jest sensowne tylko wtedy, gdy jesteś z kontekstem MVC Spring, więc kontroler @nie służy rzeczywistemu celowi w Twoim kodzie. Nadal możesz wstrzyknąć fasolę do dowolnego miejsca za pomocą zakresu sesji / zakresu żądania ( nie potrzebujesz Spring MVC / Controller, aby wstrzyknąć fasolę w określonym zakresie).
Update :
RequestContextListener wyświetla żądanie tylko w bieżącym wątku.
masz autowired ReportBuilder w dwóch miejscach
1. ReportPage
- widać, że Spring poprawnie wstrzyknął Kreator raportów, ponieważ wciąż jesteśmy w tym samym wątku sieciowym. zmieniłem kolejność Twojego kodu, aby upewnić się, że ReportBuilder wstrzykuje się do ReportPage w ten sposób.
log.info("ReportBuilder name: {}", reportBuilder.getName());
reportController.getReportData();
Wiedziałem, że dziennik powinien iść po zgodnie z Twoją logiką, tylko w celu debugowania dodałem .
2. UselessTasklet
- mamy wyjątek, ponieważ jest to inny wątek utworzony przez Spring Batch, gdzie żądanie nie jest ujawniane przez RequestContextListener
.
Należy mieć inną logikę tworzenia i wstrzykiwania instancji ReportBuilder
do Spring Batch (może Spring Batch parametry i za pomocą Future<ReportBuilder>
można zwrócić w przyszłości)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-28 00:19:37
Naprawiłem ten problem, dodając następujący kod w moim pliku.
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
Konfiguracja XML -
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
Powyżej możemy wykonać konfigurację Javy -
@Configuration
@WebListener
public class MyRequestContextListener extends RequestContextListener {
}
Jak dodać RequestContextListener bez konfiguracji xml?
Używam wersji wiosennej 5.1.4.Uwolnienie i nie ma potrzeby. aby dodać poniżej zmiany w pom.
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.10</version>
</dependency>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-13 14:14:29
Https://stackoverflow.com/a/30640097/2569475
W tym przypadku sprawdź moją odpowiedź pod podanym adresem url
Używanie zasięgu żądania poza rzeczywistym żądaniem www
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:30
Moja odpowiedź odnosi się do szczególnego przypadku ogólnego problemu opisanego przez OP, ale dodam go na wypadek, gdyby komuś pomógł.
Podczas używania @EnableOAuth2Sso
, Spring umieszcza OAuth2RestTemplate
w kontekście aplikacji, a ten komponent przyjmuje rzeczy związane z serwletem związane z wątkiem.
Mój kod ma zaplanowaną metodę asynchroniczną, która używa autowired RestTemplate
. To nie działa wewnątrz DispatcherServlet
, ale Spring wstrzykiwał OAuth2RestTemplate
, co spowodowało błąd opisany przez OP.
The roztwór miał wykonać iniekcję opartą na nazwie. W konfiguracji Javy:
@Bean
public RestTemplate pingRestTemplate() {
return new RestTemplate();
}
I w klasie, która go używa:
@Autowired
@Qualifier("pingRestTemplate")
private RestTemplate restTemplate;
Teraz Spring wstrzykuje zamierzony, pozbawiony servletów RestTemplate
.
Musisz tylko zdefiniować w fasoli gdzie potrzebujesz innego zakresu niż domyślny zakres Singletona z wyjątkiem prototypu. Na przykład:
<bean id="shoppingCart"
class="com.xxxxx.xxxx.ShoppingCartBean" scope="session">
<aop:scoped-proxy/>
</bean>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-30 02:49:44
Miał ten sam błąd, gdy miałem @Order
adnotację na klasie filtra. Nawet ty dodałem filtr przez łańcuch HttpSecurity
.
Usunąłem {[0] } i zadziałało.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-30 08:51:50