봄 부팅 임베디드 톰캣 세션 제한 시간 문제

봄 부팅 Tomcat이 최근 세션 시간 제한 문제를 구덩이하자 임베디드.

응용 프로그램이 세션 시간 제한을 설정해야합니다에서 application.properties을 다음과 같이 다음 구성 파일의 설정에 익숙해,

server.session.timeout = 90

여기에 짧은 시간 제한은 주로 어떤 일이 (30 분의 값을 설정 한 다음, 너무 비인간적으로, 그것을 볼 수 없습니다)이없는 결국보고 싶어요. 결과는이 후 발견 바이 봄 부팅에서 작동하지 않았다, 구성은 다음과 같이된다,

섬기는 사람. 서블릿 (90) = .session.timeout

그러나 결과는 여전히 다음이 간헐적으로 작동하지 않는 무지한 문제의 원인, 바이두, 구글의 다양한 발견하고 마침내 그것을 느끼거나 방법이 연구 중이다도에 의해 소스 코드를 볼 수 밖에.

이 세션 제한 시간 문제이기 때문에 1, 다음 세션의 구현을 보면 -가 StandardSession

이 isValid () 메소드

    / ** 
     *이 세션의 <코드> isValid </ 코드> 플래그를 돌려줍니다. 
     * / 
    @Override 
    공공  부울 isValid () { 

        경우 (! .isValid는) {
             반환  거짓 ; 
        } 

        경우 ( .expiring) {
             반환  사실 ; 
        } 

        경우 (ACTIVITY_CHECK && accessCount.get는 ()> 0 ) {
             반환  ; 
        } 

        경우 (maxInactiveInterval> 0 ) {
             INT timeIdle = ( INT() getIdleTimeInternal () / 1000L );
            경우 ( timeIdle> = maxInactiveInterval ) { 
                (만료 사실 ); 
            } 
        } 

        반환  .isValid을; 
    }

읽기에서, 여기  timeIdle> = maxInactiveInterval가 호출이 (참) 만료에 맞게 세션 시간 제한을 결정하기 위해 트리거됩니다. isValid ()를 호출 할 때 그래서 문제는,이됩니까?

2. 배경 확실히 isValid () 스레드를 호출 정기적으로 한

분별로, StandardManager 및 ManagerBase을 다음과 같이보기 isValid () 관련 클래스를 호출합니다.

StandardManager는 주석은 웹 컨테이너가 파괴 될 때 호출되어야하며, 모든 생존 세션이 만료되었다고 표시하는 데 사용됩니다, 그래서 우리는 ManagerBase 봐

        // 모든 활성 세션 만료 
        세션 세션 [] = 용 ) (findSessions 단계;
        위한 ( int로 ; 나는 sessions.length <I는 I = 0 ++ ) { 
            세션 세션 = 세션 [I]을;
            시도 {
                 경우 (session.isValid ()) { 
                    session.expire (); 
                } 
            } 캐치 (Throwable를 t) { 
                ExceptionUtils.handleThrowable (t); 
            } 마지막으로 {
                 // 누수 메모리에 대한 측정의 경우 세션에 대한 참조
                 //객체는 공유 필드에 어딘가에 보관 
                ) (session.recycle을; 
            } 
        }

ManagerBase는, 메모는 통화 processExpires () 클래스를 보면, 우리가 원하는 것을 보여줍니다. 또는 ManagerBase.

    / ** 
     * 이 만료 된 모든 세션을 무효로합니다.
     * / 
    공용  공극 processExpires () { 

         timeNow = System.currentTimeMillis는 (); 
        세션 세션 [] = 용 findSessions ();
        INT expireHere = 0 ; 

        경우 (log.isDebugEnabled ()) 
            log.debug ( "시작 세션 만료"+ getName () + + timeNow + "sessioncount"+ "에서" sessions.length);
        위한 ( int로 I = 0; i가 sessions.length를 <; 내가 ++ ) {
             경우 (세션 [I]! = null의 &&!세션 [I] .isValid ()) { 
                expireHere ++ ; 
            } 
        } 
         timeEnd = System.currentTimeMillis는 ();
        경우 (log.isDebugEnabled ()) 
             log.debug ( "최종 세션 만료"+ getName () + "processingTime"+ (timeEnd - timeNow) + "만료 된 세션 :"+ expireHere); 
        processingTime + = (timeEnd - timeNow); 

    }

) (processExpires 전화

    / ** 
     * 세션 만료 주파수 및 관련 관리자 작업. 
     * 관리자 작업은 지정된 시간에 대해 한 번 수행됩니다 
     (가장 자주, 낮은, 즉 양을 * backgroundProcess 통화 
     * 검사가 발생합니다). 
     * / 
    보호  INT의 processExpiresFrequency = 6 ;
    / ** 
     * { @inheritDoc } 
     * <p> 
     * {직접 호출 @link의 #processExpires는 ()}
      * / 
    @Override 
    공개  공극 backgroundProcess () { 
        카운트 = %의 (+ 1 카운트) processExpiresFrequency 단계;
        경우 (== 0 카운트 ) 
            processExpires (); 
    }

멀지 않은 진실을 알고 backgroundProcess () 메소드 이름을 참조하십시오. 어떤 전화는 StandardContext 클래스에서, 다음과 같다

    @Override
     공공  무효 backgroundProcess () { 

        경우 (! 의 getState () isAvailable ().)
             반환 ; 

        로더 로더 = getLoader ();
        경우 (! 로더 = null가 ) {
             시도 { 
                ) (loader.backgroundProcess을; 
            } 캐치 (예외 E) { 
                log.warn (sm.getString (
                         "standardContext.backgroundProcess.loader" 로더), E); 
            } 
        } 
        관리자 관리자 = getManager ();
        만약(! 매니저 = 널 (null) ) {
             시도 {
                 ) manager.backgroundProcess을 (; 
            } 캐치 (예외 전자) { 
                log.warn (sm.getString (
                         "standardContext.backgroundProcess.manager" , 관리자), 
                        전자); 
            } 
        } 
        WebResourceRoot 리소스 = 용 의 GetResources ();
        경우 (! 자원 = null가 ) {
             시도 { 
                ) (resources.backgroundProcess을; 
            } 캐치  (예외 전자) {
                log.warn (sm.getString (
                         "standardContext.backgroundProcess.resources" , 
                        자원), 전자); 
            } 
        } 
        InstanceManager instanceManager = getInstanceManager ();
        경우 (instanceManager instanceof를 DefaultInstanceManager는) {
             시도 { 
                ((DefaultInstanceManager) instanceManager) .backgroundProcess ()를; 
            } 캐치 (예외 전자) { 
                log.warn (sm.getString (
                         "standardContext.backgroundProcess.instanceManager" , 
                        자원), 전자); 
            } 
        } 
        슈퍼 .backgroundProcess (); 
    }

그러나 우리는 전화, ContainerBase.ContainerBackgroundProcessor을 계속 볼, 스레드 생성을 보지 못했다

    / ** 
     * 개인 스레드 클래스는 backgroundProcess 메서드 호출 할 
     고정 지연 후이 컨테이너와 그 아이의 *을. 
     * / 
    보호  클래스 ContainerBackgroundProcessor는 구현 의 Runnable 
                동안 (! threadDone) {
                     시도 {
                         Thread.sleep를 (backgroundProcessorDelay * 1000L을 ); 
                    } 캐치 (예외 : InterruptedException 전자) {
                         // 무시 
                    }
                     경우 (! {threadDone) 
                        processChildren (ContainerBase. ); 
                    } 
                }

새벽하세요! 모든 백그라운드 스레드 보인다  backgroundProcessorDelay의 *의 세션이 만료 여부를 결정 processExpiresFrequency (S)를.

기본값 :

backgroundProcessorDelay은 = 30

ServerProperties. 클래스 
     / ** 
         * backgroundProcess 방법의 호출 사이의 지연. 기간 접미사의 경우 
         *이 지정되지 않은 (초)이 사용됩니다. 
         * / 
        @DurationUnit (ChronoUnit.SECONDS) 
        전용 기간 backgroundProcessorDelay = Duration.ofSeconds (30);

processExpiresFrequency = 6

그래서 기본적으로 모든 3 분의 백그라운드 스레드는 초과 근무 세션 여부를 판단합니다. 그래서 효과를 볼 수 server.servlet.session.timeout = 90 년대, 결코 전에 설정합니다.

또한 분 단위로 시간 제한이 백그라운드 처리를주의, 배경, 즉 90 년대는 1 분 간주됩니다.

TomcatServletWebServerFactory. 클래스 

    개인  getSessionTimeoutInMinutes () { 
        기간 경우 SessionTimeout = 하는 getSession () getTimeout에서 ().;
        경우 (isZeroOrLess (이 경우 SessionTimeout)) {
             반환 0 ; 
        } 
        리턴 (Math.max ) sessionTimeout.toMinutes를 ( 1 ); 
    }

 

추천

출처www.cnblogs.com/hello-yz/p/10993707.html