详解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)
publicclassServerProperties
implementsEmbeddedServletContainerCustomizer,EnvironmentAware,Ordered{
//代码
}
2、上面类中“ServerProperties”继承自“EmbeddedServletContainerCustomizer”接口。重写customize方法,之后在此方法中“向上推”,即可找到“AbstractConfigurableEmbeddedServletContainer ”类。
@Override
publicvoidcustomize(ConfigurableEmbeddedServletContainercontainer){
//多个参数判断,如果在application中没配置的情况下都是null
if(getPort()!=null){
container.setPort(getPort());
}
...//n多个参数判断,
//以下的代码就是重点,因为是tomcat容器,所以以下条件为“真”,经过一系列的查找父类或者实现接口即可找到抽象类“AbstractConfigurableEmbeddedServletContainer”
//publicclassTomcatEmbeddedServletContainerFactoryextendsAbstractEmbeddedServletContainerFactoryimplementsResourceLoaderAware
//publicabstractclassAbstractEmbeddedServletContainerFactoryextendsAbstractConfigurableEmbeddedServletContainerimplementsEmbeddedServletContainerFactory
if(containerinstanceofTomcatEmbeddedServletContainerFactory){
getTomcat().customizeTomcat(this,
(TomcatEmbeddedServletContainerFactory)container);
}
//以上代码执行完成之后,实际上已经有对应的session所有的默认参数,之后通过下面方法,将所有参数放入对应的容器中。第3、4步就是设置过程
container.addInitializers(newSessionConfiguringInitializer(this.session));
}
3、在“AbstractConfigurableEmbeddedServletContainer”类中终于可以找到“超时时间”的相关设置
//重要代码
//45行
privatestaticfinalintDEFAULT_SESSION_TIMEOUT=(int)TimeUnit.MINUTES
.toSeconds(30);
//66行
privateintsessionTimeout=DEFAULT_SESSION_TIMEOUT;
@Override
publicvoidsetSessionTimeout(intsessionTimeout){
this.sessionTimeout=sessionTimeout;
}
//171-188行
@Override
publicvoidsetSessionTimeout(intsessionTimeout,TimeUnittimeUnit){
Assert.notNull(timeUnit,"TimeUnitmustnotbenull");
this.sessionTimeout=(int)timeUnit.toSeconds(sessionTimeout);
}
/**
*Returnthesessiontimeoutinseconds.
*@returnthetimeoutinseconds
*/
publicintgetSessionTimeout(){
returnthis.sessionTimeout;
}
4、执行第2步的”Container.addInitializers(newSessionConfiguringInitializer(this.session))“加载所有的配置参数。
publicstaticclassSession{
/**
*Sessiontimeoutinseconds.
*/
privateIntegertimeout;
publicIntegergetTimeout(){
returnthis.timeout;
}
//将session超时时间设置进来
publicvoidsetTimeout(IntegersessionTimeout){
this.timeout=sessionTimeout;
}
第二步:将上面的超时时间赋值给“MaxInactiveInterval”参数。
说明:既然上面tomcat需要的参数都已经加载完成,那么接下来就会运行tomcat,此处不做细讲,直接进入tomcat启动和加载参数说明。在“TomcatEmbeddedServletContainerFactory”类中的方法调用流程如下:
getEmbeddedServletContainer--》prepareContext--》configureContext--》configureSession--》getSessionTimeoutInMinutes。
1、调用configureSession设置tomcat的Session配置参数。
//以下代码
privatevoidconfigureSession(Contextcontext){
longsessionTimeout=getSessionTimeoutInMinutes();
context.setSessionTimeout((int)sessionTimeout);
Managermanager=context.getManager();
if(manager==null){
manager=newStandardManager();
//此处即为设置相应的参数的位置。之后会调用StandardContext类的setManger(Manager)方法,在setManger中会调用"manager.setContext(this)"
context.setManager(manager);
}
}
//计算超时时间为分钟(注意:此处会将之前的1800秒,转换为30分钟)。可以看出最终的时间结果是个整数的分钟类型,也就是说如果设置的超时时间(单位为秒)不是60的倍数,也会最终转换为60的倍数,并且最小超时时间设置的是60秒。
privatelonggetSessionTimeoutInMinutes(){
longsessionTimeout=getSessionTimeout();
if(sessionTimeout>0){
sessionTimeout=Math.max(TimeUnit.SECONDS.toMinutes(sessionTimeout),1L);
}
returnsessionTimeout;
}
2、最终将SessionTimeout赋值给MaxInactiveInterval。终于完成session超时时间设置。
//以下代码
@Override
publicvoidsetContext(Contextcontext){
//省略其余设置代码,直接重新设置Session超时时间,此时又将上面的分钟单位转为秒。此时终于给Sesseion设置了默认超时时间。
if(this.context!=null){
setMaxInactiveInterval(this.context.getSessionTimeout()*60);
this.context.addPropertyChangeListener(this);
}
}
三:如果自定义超时时间呢?
其实从上面的流程,已经不难看出,只需要在“org.springframework.boot.autoconfigure.web.ServerProperties”类中找到对应的Session参数,初始化让其加载上来即可完成设置。
/**
*Getthesessiontimeout.
*@returnthesessiontimeout
*@deprecatedsince1.3.0infavorof{@codesession.timeout}.
*/
@Deprecated
@DeprecatedConfigurationProperty(replacement="server.session.timeout")
publicIntegergetSessionTimeout(){
returnthis.session.getTimeout();
}
所以在application中配置“server.session.timeout“即可,参数类型为long类型,单位为”秒“。
四:运行程序是如何判断session超时的?
其实很简单:只需要在每次本次同一个sessionequest请求的时间,和之前的请求时间进行比较,发现两个值的差已经大于MaxInactiveInterval的值即可。
//判断是否超时
@Override
publicbooleanisValid(){
//省略多个条件判断
if(maxInactiveInterval>0){
//判断此session空闲时间是否比maxInactiveInterval大,如果大的情况下,session就超时
inttimeIdle=(int)(getIdleTimeInternal()/1000L);
if(timeIdle>=maxInactiveInterval){
expire(true);
}
}
returnthis.isValid;
}
//将上次访问时间和当前时间比较,拿到空闲时间值
@Override
publiclonggetIdleTimeInternal(){
longtimeNow=System.currentTimeMillis();
longtimeIdle;
if(LAST_ACCESS_AT_START){
timeIdle=timeNow-lastAccessedTime;
}else{
timeIdle=timeNow-thisAccessedTime;
}
returntimeIdle;
}
说明:
所以为了保证session超时时间长点,可以在application配置文件中配置“server.session.timeout”参数即可,参数单位为“秒”,如果参数不是60的整数倍,会转换成60的整数倍(见二:系统如何设置超时时间、步骤二中的“1”中算法)。如不满一分钟,会转换为60秒。
扩展:
实际上也可以直接重写EmbeddedServletContainerCustomizer的customize方法进行赋值。
@Bean
publicEmbeddedServletContainerCustomizercontainerCustomizer(){
returnnewEmbeddedServletContainerCustomizer(){
@Override
publicvoidcustomize(ConfigurableEmbeddedServletContainercontainer){
container.setSessionTimeout(600);//单位为S
}
};
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。