首頁  >  文章  >  Java  >  詳解SpringBoot中Session超時問題原因

詳解SpringBoot中Session超時問題原因

巴扎黑
巴扎黑原創
2018-05-10 13:49:595558瀏覽

本篇文章主要介紹了詳解SpringBoot中Session超時原理說明,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧

一:前言:

#最近支付後台登入一段時間後如果沒有任何操作,總是需要重新登入才可以繼續造訪頁面,出現這個問題的原因就是session超時,debug程式碼後發現session的超時時間是1800s。也就是說當1800秒內沒有任何操作,session就會出現超時現象。那這個超時時間是如何設定的呢?然後該如何重新設定此超時時間呢?系統又如何判斷session逾時的呢?接下來就一一進行解答。

二:系統session逾時時間如何預設的?

說明:取得session逾時時間的方法為」request.getSession().getMaxInactiveInterval()",但是tomcat中設定超時時間的參數為“sessionTimeout”,那麼他們是怎麼連結起來的呢?

第一步:載入sessionTimeout參數。

1、專案運行初始化透過「@ConfigurationProperties」註解載入「org.springframework.boot.autoconfigure.web.ServerProperties」類別。

//springBoot中默认的配置文件为"application.yml"或者"application.perties"文件,也就是说server是其中的一个配置参数。
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties
  implements EmbeddedServletContainerCustomizer, EnvironmentAware, Ordered {
//代码
}

2、上面類別中「ServerProperties」繼承自「EmbeddedServletContainerCustomizer」介面。重寫customize方法,之後在此方法中“向上推”,即可找到“AbstractConfigurableEmbeddedServletContainer  ”類別。

@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
 //多个参数判断,如果在application中没配置的情况下都是null
 if (getPort() != null) {
  container.setPort(getPort());
 }
 ...//n多个参数判断,
 //以下的代码就是重点,因为是tomcat容器,所以以下条件为“真”,经过一系列的查找父类或者实现接口即可找到抽象类“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);
 }
//以上代码执行完成之后,实际上已经有对应的session所有的默认参数,之后通过下面方法,将所有参数放入对应的容器中。第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、執行第2步驟的」Container.addInitializers(new SessionConfiguringInitializer(this.session ))「載入所有的配置參數。

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」參數。

說明:既然上面tomcat需要的參數都已經載入完成,那麼接下來就會運行tomcat,此處不做細講,直接進入tomcat啟動和載入參數說明。在「TomcatEmbeddedServletContainerFactory」類別中的方法呼叫流程如下:

getEmbeddedServletContainer--》prepareContext--》configureContext--》configureSession--》getSessionTimeoutInMinutes。

1、呼叫configureSession設定tomcat的Session設定參數

//以下代码
private void configureSession(Context context) {
 long sessionTimeout = getSessionTimeoutInMinutes();
 context.setSessionTimeout((int) sessionTimeout);
 Manager manager = context.getManager();
 if (manager == null) {
  manager = new StandardManager();
  //此处即为设置相应的参数的位置。之后会调用StandardContext类的setManger(Manager)方法,在setManger中会调用"manager.setContext(this)"
  context.setManager(manager);
 }
}
//计算超时时间为分钟(注意:此处会将之前的1800秒,转换为30分钟)。可以看出最终的时间结果是个整数的分钟类型,也就是说如果设置的超时时间(单位为秒)不是60的倍数,也会最终转换为60的倍数,并且最小超时时间设置的是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);
 }
}

三:如果自訂逾時時間呢?

其實從上面的流程,已經不難看出,只需要在「org.springframework.boot.autoconfigure.web.ServerProperties」類別中找到對應的Session參數,初始化讓其載入上來即可完成設定。

/**
 * 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「即可,參數類型為long類型,單位為」秒「。

四:執行程式是如何判斷session逾時的?

其實很簡單:只需要在每次同一個sessionequest請求的時間,和先前的請求時間進行比較,發現兩個值的差已經大於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」參數即可,參數單位為「秒”,如果參數不是60的整數倍,會轉換成60的整數倍(請參閱二:系統如何設定超時時間、步驟二中的“1”中演算法)。如不滿一分鐘,會轉換為60秒。

擴充功能:

其實也可以直接重寫EmbeddedServletContainerCustomizer的customize方法進行賦值。

 @Bean
 public EmbeddedServletContainerCustomizer containerCustomizer(){
  return new EmbeddedServletContainerCustomizer() {
   @Override
   public void customize(ConfigurableEmbeddedServletContainer container) {
     container.setSessionTimeout(600);//单位为S
   }
  };
 }

以上是詳解SpringBoot中Session超時問題原因的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn