详解SpringBoot中Session超时原理说明

作者:james__Gao 时间:2022-01-24 06:40:49 

一:前言:

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

来源:http://blog.csdn.net/gaodebao1/article/details/51789188

标签:SpringBoot,Session
0
投稿

猜你喜欢

  • Android实现简易计步器功能隔天步数清零查看历史运动纪录

    2021-07-24 00:37:02
  • 初识Spring Boot框架之Spring Boot的自动配置

    2022-08-25 10:27:57
  • C#中结构体定义并转换字节数组详解

    2023-01-23 11:07:50
  • Spring bean的实例化和IOC依赖注入详解

    2023-11-23 23:57:15
  • JNI语言基本知识

    2022-01-20 20:02:46
  • java编程创建型设计模式单例模式的七种示例

    2023-06-21 08:47:39
  • Android指纹解锁方法解析

    2023-06-27 15:37:58
  • Android编程开发ScrollView中ViewPager无法正常滑动问题解决方法

    2023-12-15 01:21:32
  • Android Monkey压力测试详细介绍

    2021-10-24 08:02:37
  • Android入门之TabHost与TabWidget实例解析

    2022-12-07 23:03:42
  • Android网络工具类NetworkUtils详解

    2022-12-08 05:18:43
  • Android悬浮按钮点击返回顶部FloatingActionButton

    2021-09-09 01:47:00
  • JAXB简介_动力节点Java学院整理

    2021-09-15 00:09:32
  • Android 媒体开发之MediaPlayer状态机接口方法实例解析

    2023-04-20 06:53:22
  • Java反射机制的实现详解

    2023-08-21 09:33:00
  • Mybatis注解增删改查的实例代码

    2022-03-31 01:26:15
  • C#多线程的Join()方法

    2022-05-08 23:56:13
  • Java线程池并发执行多个任务方式

    2023-08-14 16:26:03
  • SpringMVC拦截器创建配置及执行顺序

    2023-06-06 20:41:16
  • Android ListView和Adapter数据适配器的简单介绍

    2023-04-16 04:07:12
  • asp之家 软件编程 m.aspxhome.com