詳解SpringBoot中Session超時原理說明
一:前言:
最近支付后臺登錄一段時間后如果沒有任何操作,總是需要重新登錄才可以繼續(xù)訪問頁面,出現(xiàn)這個問題的原因就是session超時,debug代碼后發(fā)現(xiàn)session的超時時間是1800s。也就是說當1800秒內(nèi)沒有任何操作,session就會出現(xiàn)超時現(xiàn)象。那這個超時時間是如何設置的呢?然后該如何重新設置此超時時間呢?系統(tǒng)又如何判斷session超時的呢?接下來就一一進行解答。
二:系統(tǒng)session超時時間如何默認的?
說明:獲取session超時時間的方法為”request.getSession().getMaxInactiveInterval()",但是tomcat中設置超時時間的參數(shù)為“sessionTimeout”,那么他們是怎么聯(lián)系起來的呢?
第一步:加載sessionTimeout參數(shù)。
1、項目運行初始化通過“@ConfigurationProperties”注解加載“org.springframework.boot.autoconfigure.web.ServerProperties”類。
//springBoot中默認的配置文件為"application.yml"或者"application.perties"文件,也就是說server是其中的一個配置參數(shù)。
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties
implements EmbeddedServletContainerCustomizer, EnvironmentAware, Ordered {
//代碼
}
2、上面類中“ServerProperties”繼承自“EmbeddedServletContainerCustomizer”接口。重寫customize方法,之后在此方法中“向上推”,即可找到“AbstractConfigurableEmbeddedServletContainer ”類。
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
//多個參數(shù)判斷,如果在application中沒配置的情況下都是null
if (getPort() != null) {
container.setPort(getPort());
}
...//n多個參數(shù)判斷,
//以下的代碼就是重點,因為是tomcat容器,所以以下條件為“真”,經(jīng)過一系列的查找父類或者實現(xiàn)接口即可找到抽象類“AbstractConfigurableEmbeddedServletContainer”
//public class TomcatEmbeddedServletContainerFactory extends AbstractEmbeddedServletContainerFactory implements ResourceLoaderAware
//public abstract class AbstractEmbeddedServletContainerFactory extends AbstractConfigurableEmbeddedServletContainer implements EmbeddedServletContainerFactory
if (container instanceof TomcatEmbeddedServletContainerFactory) {
getTomcat().customizeTomcat(this,
(TomcatEmbeddedServletContainerFactory) container);
}
//以上代碼執(zhí)行完成之后,實際上已經(jīng)有對應的session所有的默認參數(shù),之后通過下面方法,將所有參數(shù)放入對應的容器中。第3、4步就是設置過程
container.addInitializers(new SessionConfiguringInitializer(this.session));
}
3、在“AbstractConfigurableEmbeddedServletContainer”類中終于可以找到“超時時間”的相關設置
//重要代碼
//45行
private static final int DEFAULT_SESSION_TIMEOUT = (int) TimeUnit.MINUTES
.toSeconds(30);
//66行
private int sessionTimeout = DEFAULT_SESSION_TIMEOUT;
@Override
public void setSessionTimeout(int sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
//171-188行
@Override
public void setSessionTimeout(int sessionTimeout, TimeUnit timeUnit) {
Assert.notNull(timeUnit, "TimeUnit must not be null");
this.sessionTimeout = (int) timeUnit.toSeconds(sessionTimeout);
}
/**
* Return the session timeout in seconds.
* @return the timeout in seconds
*/
public int getSessionTimeout() {
return this.sessionTimeout;
}
4、執(zhí)行第2步的”Container.addInitializers(new SessionConfiguringInitializer(this.session))“加載所有的配置參數(shù)。
public static class Session {
/**
* Session timeout in seconds.
*/
private Integer timeout;
public Integer getTimeout() {
return this.timeout;
}
//將session超時時間設置進來
public void setTimeout(Integer sessionTimeout) {
this.timeout = sessionTimeout;
}
第二步:將上面的超時時間賦值給“MaxInactiveInterval”參數(shù)。
說明:既然上面tomcat需要的參數(shù)都已經(jīng)加載完成,那么接下來就會運行tomcat,此處不做細講,直接進入tomcat啟動和加載參數(shù)說明。在“TomcatEmbeddedServletContainerFactory”類中的方法調(diào)用流程如下:
getEmbeddedServletContainer--》prepareContext--》configureContext--》configureSession--》getSessionTimeoutInMinutes。
1、調(diào)用configureSession設置tomcat的Session配置參數(shù)。
//以下代碼
private void configureSession(Context context) {
long sessionTimeout = getSessionTimeoutInMinutes();
context.setSessionTimeout((int) sessionTimeout);
Manager manager = context.getManager();
if (manager == null) {
manager = new StandardManager();
//此處即為設置相應的參數(shù)的位置。之后會調(diào)用StandardContext類的setManger(Manager)方法,在setManger中會調(diào)用"manager.setContext(this)"
context.setManager(manager);
}
}
//計算超時時間為分鐘(注意:此處會將之前的1800秒,轉換為30分鐘)??梢钥闯鲎罱K的時間結果是個整數(shù)的分鐘類型,也就是說如果設置的超時時間(單位為秒)不是60的倍數(shù),也會最終轉換為60的倍數(shù),并且最小超時時間設置的是60秒。
private long getSessionTimeoutInMinutes() {
long sessionTimeout = getSessionTimeout();
if (sessionTimeout > 0) {
sessionTimeout = Math.max(TimeUnit.SECONDS.toMinutes(sessionTimeout), 1L);
}
return sessionTimeout;
}
2、最終將SessionTimeout賦值給MaxInactiveInterval。終于完成session超時時間設置。
//以下代碼
@Override
public void setContext(Context context) {
//省略其余設置代碼,直接重新設置Session超時時間,此時又將上面的分鐘單位轉為秒。此時終于給Sesseion設置了默認超時時間。
if (this.context != null) {
setMaxInactiveInterval(this.context.getSessionTimeout() * 60);
this.context.addPropertyChangeListener(this);
}
}
三:如果自定義超時時間呢?
其實從上面的流程,已經(jīng)不難看出,只需要在“org.springframework.boot.autoconfigure.web.ServerProperties”類中找到對應的Session參數(shù),初始化讓其加載上來即可完成設置。
/**
* Get the session timeout.
* @return the session timeout
* @deprecated since 1.3.0 in favor of {@code session.timeout}.
*/
@Deprecated
@DeprecatedConfigurationProperty(replacement = "server.session.timeout")
public Integer getSessionTimeout() {
return this.session.getTimeout();
}
所以在application中配置“server.session.timeout“即可,參數(shù)類型為long類型,單位為”秒“。
四:運行程序是如何判斷session超時的?
其實很簡單:只需要在每次本次同一個sessionequest請求的時間,和之前的請求時間進行比較,發(fā)現(xiàn)兩個值的差已經(jīng)大于MaxInactiveInterval的值即可。
//判斷是否超時
@Override
public boolean isValid() {
//省略多個條件判斷
if (maxInactiveInterval > 0) {
//判斷此session空閑時間是否比maxInactiveInterval大,如果大的情況下,session就超時
int timeIdle = (int) (getIdleTimeInternal() / 1000L);
if (timeIdle >= maxInactiveInterval) {
expire(true);
}
}
return this.isValid;
}
//將上次訪問時間和當前時間比較,拿到空閑時間值
@Override
public long getIdleTimeInternal() {
long timeNow = System.currentTimeMillis();
long timeIdle;
if (LAST_ACCESS_AT_START) {
timeIdle = timeNow - lastAccessedTime;
} else {
timeIdle = timeNow - thisAccessedTime;
}
return timeIdle;
}
說明:
所以為了保證session超時時間長點,可以在application配置文件中配置“server.session.timeout”參數(shù)即可,參數(shù)單位為“秒”,如果參數(shù)不是60的整數(shù)倍,會轉換成60的整數(shù)倍(見二:系統(tǒng)如何設置超時時間、步驟二中的“1”中算法)。如不滿一分鐘,會轉換為60秒。
擴展:
實際上也可以直接重寫EmbeddedServletContainerCustomizer的customize方法進行賦值。
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer(){
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setSessionTimeout(600);//單位為S
}
};
}
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
SpringBoot項目攔截器獲取Post方法的請求body實現(xiàn)
本文主要介紹了SpringBoot項目攔截器獲取Post方法的請求body,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01
Java多線程中的ReentrantLock可中斷鎖詳細解讀
這篇文章主要介紹了Java多線程中的ReentrantLock可中斷鎖詳細解讀,ReentrantLock中的lockInterruptibly()方法使得線程可以在被阻塞時響應中斷,比如一個線程t1通過lockInterruptibly()方法獲取到一個可重入鎖,并執(zhí)行一個長時間的任務,需要的朋友可以參考下2023-12-12
利用Java的Struts框架實現(xiàn)電子郵件發(fā)送功能
這篇文章主要介紹了利用Java的Struts框架實現(xiàn)電子郵件發(fā)送功能,Struts框架是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2015-12-12
淺談Java中Map和Set之間的關系(及Map.Entry)
這篇文章主要介紹了淺談Java中Map和Set之間的關系(及Map.Entry),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09

