关于使用了@EnableRedisHttpSession注解,在配置文件中加入timeout 无效的原因

2022-07-25,,,,

spring:
  session:
    timeout: 120

首先看下@EnableRedisHttpSession注解属性

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(RedisHttpSessionConfiguration.class)
@Configuration(proxyBeanMethods = false)
public @interface EnableRedisHttpSession {

   /**
    * The session timeout in seconds. By default, it is set to 1800 seconds (30 minutes).
    * This should be a non-negative integer.
    * @return the seconds a session can be inactive before expiring
    */
   int maxInactiveIntervalInSeconds() default MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
  
   String redisNamespace() default RedisIndexedSessionRepository.DEFAULT_NAMESPACE;
   @Deprecated
   RedisFlushMode redisFlushMode() default RedisFlushMode.ON_SAVE;

   FlushMode flushMode() default FlushMode.ON_SAVE;

   String cleanupCron() default RedisHttpSessionConfiguration.DEFAULT_CLEANUP_CRON;

   SaveMode saveMode() default SaveMode.ON_SET_ATTRIBUTE;

}

可见默认时间 maxInactiveIntervalInSeconds 为30 min

这里先说结果:
如果配置了@EnableRedisHttpSession 注解,在配置文件中设置超时时间是无效的。
只能在@EnableRedisHttpSession声明超时时间是有效的

@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 120)//设置超时时间是120秒

原因
配置文件中的spring.session.timout的作用值,会在RedisSessionConfiguration 起作用

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ RedisTemplate.class, RedisIndexedSessionRepository.class })
@ConditionalOnMissingBean(SessionRepository.class)
@ConditionalOnBean(RedisConnectionFactory.class)
@Conditional(ServletSessionCondition.class)
@EnableConfigurationProperties(RedisSessionProperties.class)
class RedisSessionConfiguration {

   	@Autowired
   	public void customize(SessionProperties sessionProperties, RedisSessionProperties redisSessionProperties,
   			ServerProperties serverProperties) {  
   			// 获取配置文件的超时时间
   		Duration timeout = sessionProperties
   				.determineTimeout(() -> serverProperties.getServlet().getSession().getTimeout());
   		if (timeout != null) {
   			setMaxInactiveIntervalInSeconds((int) timeout.getSeconds());
   		}
   		setRedisNamespace(redisSessionProperties.getNamespace());
   		setFlushMode(redisSessionProperties.getFlushMode());
   		setSaveMode(redisSessionProperties.getSaveMode());
   		setCleanupCron(redisSessionProperties.getCleanupCron());
   	}
   }
}

如果标注了@EnableRedisHttpSession 注解,这个类就不会被加载,不会起作用了。
原因:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(RedisHttpSessionConfiguration.class)  // @EnableRedisHttpSession  给容器中导入 RedisHttpSessionConfiguration 组件
@Configuration(proxyBeanMethods = false) 
public @interface EnableRedisHttpSession {

RedisHttpSessionConfiguration有两个核心的地方

// 1 给容器中加入 RedisIndexedSessionRepository  这个是真正对redis操作的组件,超时时间也在这个组件中真正的起作用
@Bean
   public RedisIndexedSessionRepository sessionRepository() {
   	RedisTemplate<Object, Object> redisTemplate = createRedisTemplate();
   	RedisIndexedSessionRepository sessionRepository = new RedisIndexedSessionRepository(redisTemplate);
   	sessionRepository.setApplicationEventPublisher(this.applicationEventPublisher);
   	if (this.indexResolver != null) {
   		sessionRepository.setIndexResolver(this.indexResolver);
   	}
   	if (this.defaultRedisSerializer != null) {
   		sessionRepository.setDefaultSerializer(this.defaultRedisSerializer);
   	}
   	// 真正超时时间起作用的地方
   	sessionRepository.setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
   	if (StringUtils.hasText(this.redisNamespace)) {
   		sessionRepository.setRedisKeyNamespace(this.redisNamespace);
   	}
   	sessionRepository.setFlushMode(this.flushMode);
   	sessionRepository.setSaveMode(this.saveMode);
   	int database = resolveDatabase();
   	sessionRepository.setDatabase(database);
   	this.sessionRepositoryCustomizers
   			.forEach((sessionRepositoryCustomizer) -> sessionRepositoryCustomizer.customize(sessionRepository));
   	return sessionRepository;
   }
// 2  解析 @EnableRedisHttpSession 注解,并且获取注解的属性
@Override
   @SuppressWarnings("deprecation")
   public void setImportMetadata(AnnotationMetadata importMetadata) {
   	Map<String, Object> attributeMap = importMetadata
   			.getAnnotationAttributes(EnableRedisHttpSession.class.getName());
   	AnnotationAttributes attributes = AnnotationAttributes.fromMap(attributeMap);
   	// 获取注解中的超时时间
   	this.maxInactiveIntervalInSeconds = attributes.getNumber("maxInactiveIntervalInSeconds");
   	String redisNamespaceValue = attributes.getString("redisNamespace");
   	if (StringUtils.hasText(redisNamespaceValue)) {
   		this.redisNamespace = this.embeddedValueResolver.resolveStringValue(redisNamespaceValue);
   	}
   	FlushMode flushMode = attributes.getEnum("flushMode");
   	RedisFlushMode redisFlushMode = attributes.getEnum("redisFlushMode");
   	if (flushMode == FlushMode.ON_SAVE && redisFlushMode != RedisFlushMode.ON_SAVE) {
   		flushMode = redisFlushMode.getFlushMode();
   	}
   	this.flushMode = flushMode;
   	this.saveMode = attributes.getEnum("saveMode");
   	String cleanupCron = attributes.getString("cleanupCron");
   	if (StringUtils.hasText(cleanupCron)) {
   		this.cleanupCron = cleanupCron;
   	}
   }

当标注了这个注解后,RedisHttpSessionConfiguration就会生效,首先会解读@EnableRedisHttpSession 注解的属性,然后在容器中加入RedisIndexedSessionRepository 组件,会把注解中的超时时间值拿来,但是,此时的RedisSessionConfiguration配置就不会起作用,因为

@Configuration
@ConditionalOnClass({ RedisTemplate.class, RedisOperationsSessionRepository.class })
@ConditionalOnMissingBean(SessionRepository.class)  // 容器中没有SessionRepository 组件采用起作用,但是我们已经给容器中加入了RedisIndexedSessionRepository
@ConditionalOnBean(RedisConnectionFactory.class)
@Conditional(ServletSessionCondition.class)
@EnableConfigurationProperties(RedisSessionProperties.class)
class RedisSessionConfiguration {

所以下面的自动装配方法也不会起作用了,配置文件的属性spring.session.timout也就不会起作用了。

当然,如果关闭 @EnableRedisHttpSession 注解,配置文件的属性spring.session.timout就会起作用,此时的调用顺序: 先加载RedisSessionConfiguration 组件,然后调用自动装配的customize方法

public void customize(SessionProperties sessionProperties, RedisSessionProperties redisSessionProperties)

然后 加载 RedisHttpSessionConfiguration 类中的RedisIndexedSessionRepository 组件,此时解析注解@EnableRedisHttpSessionsetImportMetadata方法,不会在起作用。
这也就解释了为什么加入 @EnableRedisHttpSession 配置文件属性不起作用的原因。
个人认为,不加@EnableRedisHttpSession 注解,SpringSession功能也可以开启,如果有错,可以在评论区指出。

本文地址:https://blog.csdn.net/firstbaby/article/details/112008322

《关于使用了@EnableRedisHttpSession注解,在配置文件中加入timeout 无效的原因.doc》

下载本文的Word格式文档,以方便收藏与打印。