我目前在 Tomcat 9 上部署了一个 Spring MVC 应用程序,我希望通过集成 Redis 来增强其会话管理。该应用程序当前使用 Spring Session 和 Tomcat 的默认会话管理,但我们希望切换到 Redis 以获得更好的可扩展性和持久性。
以下是我们当前设置和我们打算实施的更改的概述:
当前设置:
<!-- Dependencies for Spring Session with Redis -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-core</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.3.1.RELEASE</version>
</dependency>
目标:
在Spring MVC应用程序中实现基于Redis的会话管理。 使用 Redis 确保会话数据的可扩展性和持久性。 到目前为止我所做的:
添加了 Spring Session 与 Redis 的必要依赖关系(使用 Lettuce 作为 Redis 客户端)。 配置 Spring Session 以使用 Redis 进行会话管理。
遇到的问题:
虽然我在配置 Redis 进行会话管理方面取得了进展,但在设置会话 ID 解析器和正确配置 Redis 连接方面遇到了问题。当我使用 redis-cli 检查 redis 数据时,我可以创建会话。我不确定我当前的配置是否正确,或者是否需要采取其他步骤来确保一切顺利进行。
代码片段:
@PropertySource(value = "file:${APP_CONFIG}/redis.properties", ignoreResourceNotFound = false)
@EnableRedisHttpSession(redisNamespace = "spring:session:demo", cleanupCron = "0 */5 * * * ?", flushMode = FlushMode.IMMEDIATE, saveMode = SaveMode.ALWAYS)
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
@Value("${redis.port}")
private Integer redisPort;
@Value("${redis.host}")
private String redisHost;
@Value("${redis.pass}")
private String redisPassword;
private static final Logger log = LoggerFactory.getLogger(SessionConfig.class);
@Bean
@Primary
public LettuceConnectionFactory redisConnectionFactory() {
log.error("Creating LettuceConnectionFactory with Redis host: {} and port: {}", redisHost, redisPort);
final RedisStandaloneConfiguration redisStandaloneConfig = new RedisStandaloneConfiguration();
redisStandaloneConfig.setHostName(redisHost);
redisStandaloneConfig.setPort(redisPort);
redisStandaloneConfig.setPassword(redisPassword);
final LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfig);
// lettuceConnectionFactory.setValidateConnection(true);
lettuceConnectionFactory.setEagerInitialization(true);
lettuceConnectionFactory.afterPropertiesSet();
return lettuceConnectionFactory;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public HttpSessionIdResolver httpSessionIdResolver() {
CookieHttpSessionIdResolver resolver = new CookieHttpSessionIdResolver();
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
cookieSerializer.setCookieName("JSESSIONID"); //
cookieSerializer.setCookiePath("/");
cookieSerializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
cookieSerializer.setUseBase64Encoding(true);
resolver.setCookieSerializer(cookieSerializer);
return resolver;
}
}
观察结果:
多个 JSESSIONID 值:在浏览器中加载登录页面时,我注意到生成了两个 JSESSIONID 值。一个似乎是由 Redis 创建的,而另一个似乎与 Tomcat 的会话管理机制相关。
Redis 会话 ID 的一致性:身份验证成功后,我已验证从 Redis 检索到的会话 ID 是否与数据库中存储的会话 ID 相匹配。
不一致的会话检索:在我的代码的某些部分中,当尝试使用 RequestContextHolder 访问会话时,我获取的是 Tomcat 会话 ID(JSESSIONID 值),而不是由 Redis 管理的会话 ID。
在下面的代码中,我获取了 Redis 生成的会话 ID:
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
HttpSession session = request.getSession(true);
//other codes
}
在下面,我得到了 Tomcat 会话 JSESSIONID:
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpSession session = requestAttributes.getRequest().getSession();
请检查您的项目中的依赖项。 pom.xml 或 gradle.build 有问题。您在项目中使用多个会话尝试将其删除