欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解SpringBoot中Session超时原理说明

程序员文章站 2024-02-23 16:01:46
一:前言: 最近支付后台登录一段时间后如果没有任何操作,总是需要重新登录才可以继续访问页面,出现这个问题的原因就是session超时,debug代码后发现sessio...

一:前言:

最近支付后台登录一段时间后如果没有任何操作,总是需要重新登录才可以继续访问页面,出现这个问题的原因就是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
   }
  };
 }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。