봄 부팅 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 ); }