Explain Session timeout principle in detail in SpringBoot

  • 2020-09-16 07:27:14
  • OfStack

1. Introduction:

The reason for this problem is that session timed out. The debug code found that session timed out to 1800s. In other words, session will time out when there is no operation for 1800 seconds. So how is this timeout set? Then how do you reset this timeout? How does the system determine the session timeout? So let's do 11.

2: How to default session timeout?

Note: The session timeout is obtained by "request.getSession ().getMaxInactiveInterval ()", but the tomcat timeout parameter is" sessionTimeout ". How do they relate?

Step 1: Load the sessionTimeout parameter.

1, project initialization running through "@ ConfigurationProperties annotation" loading "org. springframework. boot. autoconfigure. web. ServerProperties" class.


//springBoot The default configuration file is "application.yml" or "application.perties" File, in other words server Is one of the 1 Three configuration parameters. 
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties
  implements EmbeddedServletContainerCustomizer, EnvironmentAware, Ordered {
// code 
}

2. "ServerProperties" in the above class inherits from the "EmbeddedServletContainerCustomizer" interface. Override the customize method and then "push up" in the method to find the "AbstractConfigurableEmbeddedServletContainer" class.


@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
 // Multiple parameters are judged if at application If it's not configured in null
 if (getPort() != null) {
  container.setPort(getPort());
 }
 ...//n Multiple parameter judgment, 
 // The following code is the point, because it is tomcat Container, so the following condition is "true" after 1 A series of searches for the parent class or implementation interface to find the abstract class. 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);
 }
// After the above code is executed, there is actually a corresponding session All the default parameters, and then put all the parameters into the corresponding container by the following method. The first 3 , 4 Step is the setup process 
 container.addInitializers(new SessionConfiguringInitializer(this.session));
}

3. You can finally find the Settings for timeout in the AbstractConfigurableEmbeddedServletContainer class


// Important code 
//45 line 
private static final int DEFAULT_SESSION_TIMEOUT = (int) TimeUnit.MINUTES
  .toSeconds(30);
//66 line 
private int sessionTimeout = DEFAULT_SESSION_TIMEOUT;
 
@Override
public void setSessionTimeout(int sessionTimeout) {
 this.sessionTimeout = sessionTimeout;
}
//171-188 line 
@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. Perform "Container.addInitializers (new SessionConfiguringInitializer(this.session)" in step 2 to load all configuration parameters.


public static class Session {

 /**
 * Session timeout in seconds.
 */
 private Integer timeout;

 public Integer getTimeout() {
  return this.timeout;
 }
// will session Timeout comes in 
 public void setTimeout(Integer sessionTimeout) {
  this.timeout = sessionTimeout;
 }

Step 2: Assign the above timeout to the "MaxInactiveInterval" parameter.

Note: Now that all the parameters required by tomcat above have been loaded, then tomcat will be run. Without going into details here, enter the boot and load parameters instructions of tomcat directly. The flow of method calls in the "TomcatEmbeddedServletContainerFactory" class is as follows:

getEmbeddedServletContainer-- prepareContext-- configureContext-- configureSession-- getSessionTimeoutInMinutes.

1. Call configureSession to set Session configuration parameters of tomcat.


// The following code 
private void configureSession(Context context) {
 long sessionTimeout = getSessionTimeoutInMinutes();
 context.setSessionTimeout((int) sessionTimeout);
 Manager manager = context.getManager();
 if (manager == null) {
  manager = new StandardManager();
  // This is where the corresponding parameter is set. And then it will call StandardContext Of the class setManger ( Manager ) Method, in setManger Will call "manager.setContext(this)"
  context.setManager(manager);
 }
}
// Calculate the timeout in minutes (note: here will be the previous 1800 Seconds, convert to theta 30 Minutes). You can see that the final time result is of integer minute type, that is, if the timeout (in seconds) set is not 60 I'm going to end up with a multiple of theta 60 Is a multiple of, and the minimum timeout is set to 60 Seconds. 
private long getSessionTimeoutInMinutes() {
 long sessionTimeout = getSessionTimeout();
 if (sessionTimeout > 0) {
  sessionTimeout = Math.max(TimeUnit.SECONDS.toMinutes(sessionTimeout), 1L);
 }
 return sessionTimeout;
}

2. Finally assign SessionTimeout to MaxInactiveInterval. The session timeout setting is finally complete.


// The following code 
@Override
public void setContext(Context context) {
 // Omit the rest of the setup code and simply reset Session Time out, at which point the above minutes are converted to seconds. At this point finally Sesseion The default timeout period is set. 
 if (this.context != null) {
  setMaxInactiveInterval(this.context.getSessionTimeout() * 60);
  this.context.addPropertyChangeListener(this);
 }
}

3: What about custom timeouts?

In fact, from the above process, is not difficult to see, only need to "org. springframework. boot. autoconfigure. web. ServerProperties" class find corresponding Session parameters, the initialization can complete set to load it.


/**
 * 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();
}

Therefore, "ES105en.session.timeout" can be configured in application. The parameter type is long and the unit is "seconds".

4: How does the runtime judge session timeout?

In fact, it is quite simple: you only need to compare the time of each sessionequest request with the previous request time and find that the difference between the two values is already greater than the value of MaxInactiveInterval.


// Determine whether it has timed out 
@Override
public boolean isValid() {
 // Omit multiple conditional judgments 
 if (maxInactiveInterval > 0) {
  // Determine the session Whether idle time ratio maxInactiveInterval Student: Big, if big case, session Just a timeout 
  int timeIdle = (int) (getIdleTimeInternal() / 1000L);
  if (timeIdle >= maxInactiveInterval) {
   expire(true);
  }
 }
 return this.isValid;
}
// Compare the last access time to the current time to get the free time value 
@Override
public long getIdleTimeInternal() {
 long timeNow = System.currentTimeMillis();
 long timeIdle;
 if (LAST_ACCESS_AT_START) {
  timeIdle = timeNow - lastAccessedTime;
 } else {
  timeIdle = timeNow - thisAccessedTime;
 }
 return timeIdle;
}

Description:

Therefore, in order to ensure a longer session timeout, the parameter "server.session.timeout" can be configured in the application configuration file. The parameter is in "seconds". If the parameter is not an integer multiple of 60, it will be converted to an integer multiple of 60 (see 2: How the system sets the timeout, the algorithm in Step 2, "1"). If less than 1 minute, it will be converted to 60 seconds.

Extension:

You can actually override the customize method of EmbeddedServletContainerCustomizer for assignment as well.


 @Bean
 public EmbeddedServletContainerCustomizer containerCustomizer(){
  return new EmbeddedServletContainerCustomizer() {
   @Override
   public void customize(ConfigurableEmbeddedServletContainer container) {
     container.setSessionTimeout(600);// The unit is S
   }
  };
 }


Related articles: