sourcetip

범위 '세션'이 현재 스레드에 대해 활성화되지 않았습니다. 불법 상태 예외:스레드 바인딩된 요청을 찾을 수 없습니다.

fileupload 2023. 7. 27. 22:12
반응형

범위 '세션'이 현재 스레드에 대해 활성화되지 않았습니다. 불법 상태 예외:스레드 바인딩된 요청을 찾을 수 없습니다.

세션별로 고유한 컨트롤러가 있습니다.스프링 문서에 따르면 구현에는 두 가지 세부 사항이 있습니다.

초기 웹 구성

요청, 세션 및 글로벌 세션 수준(웹 범위 콩)에서 콩 범위를 지정하려면 콩을 정의하기 전에 몇 가지 사소한 초기 구성이 필요합니다.

저는 제 내추다습니가에 web.xml설명서에 표시된 대로:

<listener>
  <listener-class>
    org.springframework.web.context.request.RequestContextListener
  </listener-class>
</listener>

종속성으로서의 스코프 원두

HTTP 요청 범위 빈을 다른 빈에 주입하려면(예를 들어) 범위 빈 대신 AOP 프록시를 주입해야 합니다.

나는 콩에 주석을 달았습니다.@Scope공는하를 proxyMode아래와 같이:

@Controller
@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class ReportBuilder implements Serializable {
    ...
    ...
}

문제

위의 구성에도 불구하고 다음과 같은 예외가 발생합니다.

기관.스프링 골조콩 공장콩 창조예외:이름이 'scopeTarget.reportBuilder'인 빈을 만드는 동안 오류가 발생했습니다. 현재 스레드에 대해 스코프 '세션'이 활성화되지 않았습니다. 싱글톤에서 이 빈을 참조하려면 이 빈에 대한 범위가 지정된 프록시를 정의하십시오. 중첩된 예외는 java.lang입니다.잘못된 상태 예외:스레드 바인딩된 요청을 찾을 수 없습니다.실제 웹 요청 외부의 요청 속성을 말하는 것입니까, 아니면 원래 수신 스레드 외부의 요청을 처리하는 것입니까?실제로 웹 요청 내에서 작업 중이고 여전히 이 메시지가 표시되는 경우 코드가 DispatcherServlet/DispatcherPortlet 외부에서 실행되고 있을 수 있습니다.이 경우 RequestContextListener 또는 RequestContextFilter를 사용하여 현재 요청을 표시합니다.

업데이트 1

아래는 나의 구성요소 스캔입니다.는 항있다이니습목에 과 같은 것이 .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>

그리고 그고다은에 .AppConfig.java:

@Configuration
@EnableAsync
@EnableCaching
@ComponentScan("org.example")
@ImportResource("classpath:applicationContext.xml")
public class AppConfig implements AsyncConfigurer {
  ...
  ...
}

업데이트 2

재현 가능한 테스트 케이스를 만들었습니다.이것은 훨씬 작은 프로젝트이기 때문에 차이점이 있지만 같은 오류가 발생합니다.파일이 꽤 많아서 제가 파일을 올렸습니다.tar.gz메가 파일 업로드.

문제는 스프링 주석이 아니라 설계 패턴에 있습니다.다양한 범위와 스레드를 함께 사용할 수 있습니다.

  • 싱글톤
  • 세션(또는 요청)
  • 스레드 풀의 작업

싱글톤은 어디서나 구매 가능합니다, 괜찮습니다.그러나 요청에 연결된 스레드 외부에서는 세션/요청 범위를 사용할 수 없습니다.

요청 또는 세션이 더 이상 존재하지 않는 경우에도 비동기 작업을 실행할 수 있으므로 요청/세션 종속 빈을 사용할 수 없습니다.또한 별도의 스레드에서 작업을 실행 중인 경우 어떤 스레드가 원본 요청인지 알 수 없습니다(이 경우 aop:proxy는 유용하지 않음을 의미함).


당신의 코드는 ReportController, ReportBuilder, DisuseTask, ReportPage 간의 계약을 원하는 것처럼 보입니다.쓸모없는 작업의 데이터를 저장하고 ReportController 또는 ReportPage에서 읽고 ReportBuilder를 더 이상 사용하지 않는 단순 클래스(POJO)를 사용하는 방법이 있습니까?

원인과 가능한 해결책에 대한 더 나은 개요를 제공하기 때문에 저는 제 자신의 질문에 답하고 있습니다.@Martin이 원인을 지목했기 때문에 저는 그에게 보너스를 수여했습니다.

원인

@Martin이 제안한 바와 같이 원인은 여러 스레드의 사용입니다.스프링 가이드에 언급된 바와 같이 요청 개체는 이러한 스레드에서 사용할 수 없습니다.

DispatcherServlet,RequestContextListener그리고.RequestContextFilter모두 동일한 작업을 수행합니다. 즉, HTTP 요청 개체를 해당 요청을 처리하는 스레드에 바인딩합니다.이를 통해 요청 및 세션 범위가 지정된 빈을 콜 체인 아래에서 사용할 수 있습니다.

솔루션 1

요청 개체를 다른 스레드에서 사용할 수 있도록 만들 수 있지만 시스템에 몇 가지 제한이 적용되어 일부 프로젝트에서는 사용할 수 없습니다.멀티 스레드애플리케이션의 요청 범위액세스에서 이 솔루션을 얻었습니다.

저는 이 문제를 간신히 모면했습니다.사용하기 시작했습니다.SimpleAsyncTaskExecutorWorkManagerTaskExecutor/ThreadPoolExecutorFactoryBean은 점은입니다.SimpleAsyncTaskExecutor스레드를 다시 사용하지 않습니다.그것은 해결책의 절반에 불과합니다.해결책의 나머지 절반은 다음을 사용하는 것입니다.RequestContextFilterRequestContextListener.RequestContextFilter및 (뿐만아니라)▁(DispatcherServlet)가 있습니다.threadContextInheritable기본적으로 자식 스레드가 부모 컨텍스트를 상속할 수 있도록 허용하는 속성입니다.

솔루션 2

다른 유일한 옵션은 요청 스레드 내에서 세션 범위 빈을 사용하는 것입니다.저의 경우 다음과 같은 이유로 불가능했습니다.

  1. 컨트롤러 메소드에는 다음과 같은 주석이 달립니다.@Async;
  2. 컨트롤러 방법은 병렬 작업 단계에 스레드를 사용하는 배치 작업을 시작합니다.

만약 다른 누군가가 같은 점을 고집한다면, 팔로우는 나의 문제를 해결했습니다.

web.xml에서

 <listener>
            <listener-class>
                    org.springframework.web.context.request.RequestContextListener 
            </listener-class>
  </listener>

세션 내 구성 요소

@Component
@Scope(value = "session",  proxyMode = ScopedProxyMode.TARGET_CLASS)

pom.xml에서

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.1</version>
    </dependency>

파일에 다음 코드를 추가하여 이 문제를 해결했습니다.

@Component
@Scope(value = "session",  proxyMode = ScopedProxyMode.TARGET_CLASS)

XML 구성 -

<listener>
        <listener-class>
            org.springframework.web.context.request.RequestContextListener 
        </listener-class>
</listener>

위에서 우리는 Java 구성을 사용할 수 있습니다.

@Configuration
@WebListener
public class MyRequestContextListener extends RequestContextListener {
}

no-xml 구성으로 RequestContextListener를 추가하는 방법은 무엇입니까?

봄 버전 5.1.4를 사용하고 있습니다.릴리스 및 폼의 아래 변경 사항을 추가할 필요가 없습니다.

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.10</version>
</dependency>

설명서에 따라:

Spring Web MVC, 즉 Spring Dispatcher Servlet 또는 Dispatcher Portlet에서 처리되는 요청 내에서 스코프 빈에 액세스하는 경우 특별한 설정이 필요하지 않습니다. Dispatcher Servlet 및 Dispatcher Portlet은 이미 모든 관련 상태를 노출합니다.

Spring MVC(Dispatch Servlet에서 처리되지 않음) 외부에서 실행 중인 경우에는RequestContextListener뿐만 아니라.ContextLoaderListener.

web.xml에 다음을 추가합니다.

   <listener>
            <listener-class>
                    org.springframework.web.context.request.RequestContextListener 
            </listener-class>
    </listener>        

그 범위에서 콩을 유지하기 위해 스프링에 세션을 제공할 것입니다.

업데이트 : 다른 답변에 따르면,@ControllerSpring MVC Context 내에 있을 때만 sense가 가능합니다. 따라서 @Controller는 코드에서 실제 목적을 수행하지 않습니다.그래도 세션 범위/요청 범위(특정 범위에서 콩을 주입하는 데 스프링 MVC/컨트롤러가 필요하지 않음)를 통해 어디든 콩을 주입할 수 있습니다.

업데이트 : RequestContextListener는 요청을 현재 스레드에만 표시합니다.
보고서 작성기 자동 배선이 두 곳에 있습니다.

1. ReportPageSpring이 보고서 작성기를 올바르게 삽입한 것을 볼 수 있습니다. 아직 동일한 웹 스레드에 있기 때문입니다.저는 ReportPage에 ReportBuilder가 이렇게 삽입되었는지 확인하기 위해 당신의 코드 순서를 변경했습니다.

log.info("ReportBuilder name: {}", reportBuilder.getName());
reportController.getReportData();

저는 당신의 논리대로 로그가 뒤따라야 한다는 것을 알았습니다, 단지 디버깅 목적으로 추가했습니다.


2. UselessTasklet예외가 발생했습니다. 이는 요청이 노출되지 않는 Spring Batch에서 생성된 다른 스레드이기 때문입니다.RequestContextListener.


생성하고 주입하려면 다른 논리가 있어야 합니다.ReportBuilder인스턴스(instance to Spring Batch)(May Spring Batch 매개변수 및 사용)Future<ReportBuilder>나중에 참조할 수 있도록 반환할 수 있습니다.)

제 답변은 OP가 설명하는 일반적인 문제의 특별한 경우를 언급하지만, 누군가에게 도움이 될 경우를 대비해 추가하겠습니다.

을 할 때@EnableOAuth2Sso봄이 오면 됩니다.OAuth2RestTemplate응용 프로그램 컨텍스트에서 이 구성 요소는 스레드 바인딩 서블릿 관련 항목을 가정합니다.

내 코드에 자동 배선을 사용하는 예약된 비동기 메서드가 있습니다.RestTemplate은 실않다지습니 안에서.DispatcherServlet하지만 스프링은 주사를 놓고 있었습니다.OAuth2RestTemplateOP가 설명하는 오류를 생성했습니다.

해결책은 이름을 기반으로 한 주입입니다.Java 구성에서 다음을 수행합니다.

@Bean
public RestTemplate pingRestTemplate() {
    return new RestTemplate();
}

그리고 그것을 사용하는 클래스에서:

@Autowired
@Qualifier("pingRestTemplate")
private RestTemplate restTemplate;

Spring은 이 없는 Spring을 합니다.RestTemplate.

https://stackoverflow.com/a/30640097/2569475

이 문제에 대해서는 위의 주어진 URL에서 내 답변을 확인하십시오.

실제 웹 요청 외부에서 요청 범위 빈 사용

내가 가지고 있었을 때 같은 오류가 있었습니다.@Order필터 클래스의 주석입니다.비록 내가 필터를 통해 추가했지만.HttpSecurity쇠사슬의

를 했습니다.@Order그리고 그것은 성공하였다.

프로토타입을 제외한 기본 싱글톤 스코프와 다른 스코프가 필요한 빈에서 정의하기만 하면 됩니다.예:

<bean id="shoppingCart" 
   class="com.xxxxx.xxxx.ShoppingCartBean" scope="session">
   <aop:scoped-proxy/> 
</bean>

언급URL : https://stackoverflow.com/questions/21286675/scope-session-is-not-active-for-the-current-thread-illegalstateexception-no

반응형