Maison  >  Article  >  Java  >  Explication détaillée des causes du problème d'expiration de session dans SpringBoot

Explication détaillée des causes du problème d'expiration de session dans SpringBoot

巴扎黑
巴扎黑original
2018-05-10 13:49:595476parcourir

Cet article présente principalement l'explication détaillée du principe du délai d'expiration de session dans SpringBoot. L'éditeur pense que c'est assez bon, je vais donc le partager avec vous maintenant et le donner comme référence. Venez jeter un œil avec l'éditeur

1 : Préface :

S'il n'y a pas d'opération après vous être connecté au paiement en arrière-plan pendant un certain temps récemment, vous devez toujours vous reconnecter avant de pouvoir continuer à accéder à la page. La raison de ce problème est que la session expire après le débogage du code. Années 1800. C'est-à-dire que lorsqu'il n'y a aucune opération dans un délai de 1 800 secondes, la session expire. Alors, comment ce délai d'attente est-il défini ? Alors comment réinitialiser ce timeout ? Comment le système détermine-t-il quand la session a expiré ? Ensuite, nous y répondrons un par un.

2 : Comment le délai d'expiration de la session système est-il défini par défaut ?

Explication : La méthode pour obtenir le délai d'expiration de la session est "request.getSession().getMaxInactiveInterval()", mais le paramètre permettant de définir le délai d'expiration dans Tomcat est "sessionTimeout". , alors Comment sont-ils connectés ?

Première étape : Chargez le paramètre sessionTimeout.

1. L'initialisation de l'opération du projet charge la classe "org.springframework.boot.autoconfigure.web.ServerProperties" via l'annotation "@ConfigurationProperties".

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

2. Les "ServerProperties" de la classe ci-dessus héritent de l'interface "EmbeddedServletContainerCustomizer". Réécrivez la méthode de personnalisation, puis "push up" dans cette méthode pour trouver la classe "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. Vous pouvez enfin trouver les paramètres pertinents de "timeout" dans la classe "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. Effectuez l'étape 2 de "Container.addInitializers (new SessionConfiguringInitializer). (this.session))"Charge tous les paramètres de configuration.

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;
 }

Étape 2 : Attribuez le délai d'expiration ci-dessus au paramètre "MaxInactiveInterval".

Remarque : Puisque les paramètres ci-dessus requis par Tomcat ont été chargés, Tomcat sera exécuté ensuite. Je n'entrerai pas dans les détails ici et passerai directement à la description des paramètres de démarrage et de chargement de Tomcat. Le processus d'appel de méthode dans la classe "TomcatEmbeddedServletContainerFactory" est le suivant :

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

1. Appelez configureSession pour définir les paramètres de configuration de session de Tomcat

//以下代码
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. Enfin, attribuez SessionTimeout à MaxInactiveInterval. Enfin terminé le réglage du délai d'expiration de la session.

//以下代码
@Override
public void setContext(Context context) {
 //省略其余设置代码,直接重新设置Session超时时间,此时又将上面的分钟单位转为秒。此时终于给Sesseion设置了默认超时时间。
 if (this.context != null) {
  setMaxInactiveInterval(this.context.getSessionTimeout() * 60);
  this.context.addPropertyChangeListener(this);
 }
}

3 : Et si le délai d'attente est personnalisé ?

En fait, à partir du processus ci-dessus, il n'est pas difficile de voir qu'il vous suffit de trouver les paramètres de session correspondants dans le fichier "org.springframework.boot.autoconfigure. web.ServerProperties". Initialisez-le et laissez-le se charger pour terminer le paramétrage.

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

Il suffit donc de configurer "server.session.timeout" dans l'application. Le type de paramètre est de type long et l'unité est "secondes".

4 : Comment le programme en cours d'exécution détermine-t-il le délai d'expiration de la session ?

C'est en fait très simple : il suffit de comparer l'heure de la même requête sessionequest avec l'heure de la requête précédente, et constater que la différence entre les deux valeurs est supérieur à MaxInactiveInterval La valeur est suffisante.

//判断是否超时
@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;
}

Remarque :

Ainsi, afin de garantir un délai d'expiration de session plus long, vous pouvez configurer le paramètre "server.session.timeout" dans le fichier de configuration de l'application. l'unité est "Secondes", si le paramètre n'est pas un multiple entier de 60, il sera converti en un multiple entier de 60 (voir 2 : Comment le système met le timeout et l'algorithme à "1" à l'étape 2). Si c'est moins d'une minute, il sera converti en 60 secondes.

Extension :

En fait, vous pouvez également remplacer directement la méthode de personnalisation d'EmbeddedServletContainerCustomizer pour l'affectation.

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn