引言:
为了查看Spring Session 的源码,需要创建一个Springboot项目,因此有了这篇笔记。
Spring Session 让支持集群会话很容易,是一个不需要依赖特定应用程序的解决方案,Spring Session Data Redis提供SessionRepository和ReactiveSessionRepository实现,Spring Session提供了以下集成
HttpSession:
允许以中立的方式替换应用程序容器(即Tomcat)中的HttpSession,支持在头中提供会话标识,以便与RESTful APIs一起工作
WebSocket:
提供在接收网络套接字消息时保持HttpSession活动的能力
WebSession:
允许以应用程序容器中立的方式替换Spring WebFlux的WebSession
那么, 当使用SpringBoot的时候,如何通过SpringSession 和Redis来支持一个Web程序的httpsession呢?
创建示例
第一步:搭建Redis测试环境
创建一个Redis Server, 可以参考上一篇文章来搭建Redis测试环境(链接:Redis 安装)
第二步:创建一个SpringBoot项目
建议通过Spring官网的Quick Start完成。 https://start.spring.io/
第三部:修改build.gradle引入依赖
在使用Spring Session之前,一个Spring Boot web应用程序必须添加以下依赖项spring-boot-starter-data-redis和spring-session-data-redis
注意 Spring Boot为Spring Session模块提供了依赖管理,所以可以不显式声明依赖版本信息
plugins {
id 'org.springframework.boot' version '2.4.8'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.springtest'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web:2.0.9.RELEASE'
//使用Spring Data Redis 和 the Lettuce client的Starter
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-redis', version: '2.3.8.RELEASE'
//Spring session依赖
implementation group: 'org.springframework.session', name: 'spring-session-data-redis', version: '2.3.0.RELEASE'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
第四步:修改application.proper中配置启动项
Spring Session配置
spring.session.store-typ表明Session的存储类型,Spring Boot应用相当于手动添加的配置@ EnableRedisHttpSession
注释,它将会创建名称springSessionRepositoryFilter
的Bean,这个Bean实现了Filter接口,通过这个接口实现了替换HttpSession,并将session保存到redis库中
spring.session.store-type=redis
flush-mode表示session保存的方式参考枚举类org.springframework.session.FlushMode
- on_save: 表示请求结束的时候保存 到redis中
- immediate: 表示创建sessionId 后直接就保存到redis 中
spring.session.redis.flush-mode=on_save
Redis连接配置
SpringBoot会自动创建RedisConnectionFactory对象,它将Spring Session连接到本地6379端口的Redis服务,产品环境也可以通过spring.redis.host修改Redis服务地址实现指向指定的Redis库
spring.redis.host=127.0.0.1
spring.redis.password=
spring.redis.port=6379
src/main/resources/application.properties完成配置参考如下:
##### Configuration the Spring session ######
# Session store type.表示session存储类型
spring.session.store-type=redis
# Session timeout 过期时间设置
server.servlet.session.timeout=3000
# Sessions flush mode.保存方式
spring.session.redis.flush-mode=on_save
# keys格式
spring.session.redis.namespace=spring:session
##### Configuring the Redis Connection ######
# Redis server host.
spring.redis.host=127.0.0.1
# Login password of the redis server.
spring.redis.password=
# Redis server port.
spring.redis.port=6379
第五步:创建LoginController用于测试
@RestController
public class LoginController {
@Autowired
private StringRedisTemplate redisTemplate;
@RequestMapping("/login")
public String login(HttpServletRequest request, String username, String password) {
if (validUser(username, password)) {
//验证成功保存sessionId和用户Id的关系
HttpSession session = request.getSession();
session.setAttribute("loginUserId", 1001);
redisTemplate.opsForValue().set("loginUser:" + 1000, session.getId());
//输出sessionId
return session.getId();
}
return "未知用户";
}
private boolean validUser(String username, String password) {
//模拟登录验证,只有admin可以登录
if (username.equals("admin")) {
return true;
} else {
return false;
}
}
}
执行登录
执行http://127.0.0.1:8080/login?username=admin&password=123456登录
执行后页面返回sessionId:c7eaf681-6503-4aa6-a15a-ec44964371fb
如图:
查看Redis中保存的信息
首先login方法中使用redisTemplate记录了登录用户和sessionId的关系
查看Session信息,
1. spring:session:sessions:c7eaf681-6503-4aa6-a15a-ec44964371fb 记录了session信息,其中key为spring:session:sessions:XXX, 可见在KEY的规则是:
配置的namespace: sessions: 生成的sessionId
如果spring.session.redis.namespace=spring:session中配置修改成spring:redis那么结果中KEY就会变成spring:redis:sessions:c7eaf681-6503-4aa6-a15a-ec44964371fb
实现原理
实现原理见我的另一篇总结 ,这里不再重复说明
问题列表
1. RedisCommandExecutionException: ERR Unsupported CONFIG异常
Caused by: io.lettuce.core.RedisCommandExecutionException: ERR Unsupported CONFIG parameter: notify-keyspace-events
at io.lettuce.core.internal.ExceptionFactory.createExecutionException(ExceptionFactory.java:137) ~[lettuce-core-6.0.6.RELEASE.jar:6.0.6.RELEASE]
at io.lettuce.core.internal.ExceptionFactory.createExecutionException(ExceptionFactory.java:110) ~[lettuce-core-6.0.6.RELEASE.jar:6.0.6.
解决方法:网上查到说是Redis数据库版本问题, 起初我使用的是2.4.5 后修改成3.2.1版本后报错解决
2. AnnotatedConnectException: Connection refused
Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: localhost/192.168.20.134:6379
Caused by: java.net.ConnectException: Connection refused: no further information
at java.base/sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) ~[na:na]
解决方法:redis.windows.conf中配置的bind 127.0.0.1,spring.redis.host配置为localhost ,所以修改spring.redis.host=127.0.0.1后报错解决