복붙노트

[SPRING] 범위 '세션'이 현재 스레드에 대해 활성화되어 있지 않습니다. IllegalStateException : 스레드 바인딩 된 요청이 없습니다.

SPRING

범위 '세션'이 현재 스레드에 대해 활성화되어 있지 않습니다. IllegalStateException : 스레드 바인딩 된 요청이 없습니다.

컨트롤러마다 고유 한 세션을 만들고 싶습니다. 스프링 문서에 따르면 구현에 대한 두 가지 세부 사항이 있습니다.

1. 초기 웹 구성

문서에 표시된대로 web.xml에 다음을 추가했습니다.

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

2. 범위가 지정된 bean을 종속 항목으로 사용

나는 아래와 같이 proxyMode를 제공하는 @Scope를 사용하여 빈에 주석을 붙였다.

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

문제

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

업데이트 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를 megafileupload에 업로드했습니다.

해결법

  1. ==============================

    1.문제는 Spring 주석이 아니라 디자인 패턴입니다. 서로 다른 범위와 스레드를 혼합합니다.

    문제는 Spring 주석이 아니라 디자인 패턴입니다. 서로 다른 범위와 스레드를 혼합합니다.

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

    비동기 작업은 요청 또는 세션이 더 이상 존재하지 않기 때문에 실행될 수 있으므로 요청 / 세션 종속 bean을 사용할 수 없습니다. 또한 별도의 스레드에서 작업을 실행하는 경우 알 수있는 방법이 없습니다. 스레드는 작성자 요청입니다 (이 경우 aop : proxy는 도움이되지 않습니다).

    나는 당신의 코드가 ReportController, ReportBuilder, UselessTask, ReportPage 사이의 계약을 만들고 싶어한다고 생각한다. 간단한 클래스 (POJO)를 사용하여 UselessTask의 데이터를 저장하고 ReportController 또는 ReportPage에서 읽고 더 이상 ReportBuilder를 사용하지 않는 방법이 있습니까?

  2. ==============================

    2.다른 사람이 같은 지점에 머물러 있다면 내 문제가 해결되었습니다.

    다른 사람이 같은 지점에 머물러 있다면 내 문제가 해결되었습니다.

    In 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>
    
  3. ==============================

    3.원인과 가능한 해결책에 대한 더 나은 개요를 제공하므로 내 자신의 질문에 대답하고 있습니다. 나는 Martin이 원인을 지적했기 때문에 @Martin에 보너스를 줬다.

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

    원인

    @Martin이 제안한 것처럼 다중 스레드를 사용하게됩니다. 요청 개체는 Spring 가이드에서 언급 한 것처럼이 스레드에서 사용할 수 없습니다.

    해결책 1

    요청 개체를 다른 스레드에서 사용할 수있게 만들 수는 있지만 시스템에 몇 가지 제한 사항이 있습니다. 이는 모든 프로젝트에서 작동하지 않을 수 있습니다. 이 솔루션은 다중 스레드 웹 응용 프로그램의 요청 범위 콩에 액세스 할 수 없습니다.

    해결책 2

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

  4. ==============================

    4.문서 별 :

    문서 별 :

    Spring MVC (DispatcherServlet에 의해 처리되지 않음) 외부에서 실행중인 경우, ContextLoaderListener뿐만 아니라 RequestContextListener를 사용해야한다.

    web.xml에 다음을 추가하십시오.

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

    그 범위에서 빈을 유지하기 위해 Spring에 세션을 제공 할 것입니다.

    업데이트 :      다른 답변에 따르면, @Controller는 Spring MVC 컨텍스트에서 작업 할 때만 의미가 있으므로 @Controller가 코드에서 실제 용도로 사용되지 않습니다. 세션 범위 / 요청 범위 (특정 범위에서 bean을 주입하기 위해 Spring MVC / Controller가 필요 없음)를 사용하여 어디에서나 빈을 삽입 할 수 있습니다.

    업데이트 :     RequestContextListener는 요청을 현재 스레드에만 공개합니다. 두 곳에서 ReportBuilder를 자동 실행했습니다.  1. ReportPage - Spring이 동일한 웹 스레드에 있기 때문에 Spring이 보고서 작성기를 제대로 주입 한 것을 볼 수 있습니다. ReportBuilder가 ReportPage에 삽입되었는지 확인하기 위해 코드의 순서를 변경했습니다.

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

    나는 로그가 당신의 논리에 따라 뒤따라야한다는 것을 알았다. 단지 디버깅 목적을 위해서였다.

    2. UselessTasklet - Request가 SpringControllerListener에 의해 노출되지 않는 Spring Batch에 의해 생성 된 다른 스레드이기 때문에 예외가 발생했습니다.

    ReportBuilder 인스턴스를 생성하고 Spring Batch에 삽입하는 다른 로직이 있어야합니다 (Spring Batch 매개 변수 및 향후 참조를 위해 반환 할 수있는 Future

  5. ==============================

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

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

    이번 호의 경우 위 URL에서 내 대답을 확인하십시오.

    실제 웹 요청 이외의 요청 범위 Bean 사용

  6. ==============================

    6.내 답변은 OP가 묘사하는 일반적인 문제의 특수한 경우를 말하지만, 누군가를 돕기 위해 추가 할 것입니다.

    내 답변은 OP가 묘사하는 일반적인 문제의 특수한 경우를 말하지만, 누군가를 돕기 위해 추가 할 것입니다.

    @ EnableOAuth2Sso를 사용할 때 Spring은 OAuth2RestTemplate을 응용 프로그램 컨텍스트에두고이 구성 요소는 스레드 바인딩 된 서블릿 관련 내용을 가정합니다.

    내 코드에는 autowired RestTemplate을 사용하는 예약 된 비동기 메소드가 있습니다. 이것은 DispatcherServlet 내에서 실행되지 않지만 Spring은 OP가 설명하는 오류를 생성 한 OAuth2RestTemplate을 주입하고있었습니다.

    해결책은 이름 기반 주입을 수행하는 것이 었습니다. 자바 설정에서 :

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

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

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

    이제 Spring은 서블릿이 필요없는 RestTemplate을 주입합니다.

  7. ==============================

    7.프로토 타입을 제외한 기본 싱글 톤 범위와는 다른 범위가 필요한 bean에서 정의 할 필요가 있습니다. 예 :

    프로토 타입을 제외한 기본 싱글 톤 범위와는 다른 범위가 필요한 bean에서 정의 할 필요가 있습니다. 예 :

    <bean id="shoppingCart" 
       class="com.xxxxx.xxxx.ShoppingCartBean" scope="session">
       <aop:scoped-proxy/> 
    </bean>
    
  8. from https://stackoverflow.com/questions/21286675/scope-session-is-not-active-for-the-current-thread-illegalstateexception-no by cc-by-sa and MIT license