基础
Spring Redis Session 作为分布式共享Session的一种解决方案,现在已经被广泛的应用,我们来看一看session 的在redis中的存储结构
结构
运行项目后,请求一次接口,进入redis中可以看到,多出来3组数据
Redis中的存储说明:
1、spring:session是默认的Redis HttpSession前缀(redis中,我们常用’:’作为分割符)。
2、每一个session都会创建3组数据
第一组:hash结构,spring-session存储的主要内容
spring:session:sessions:fc454e71-c540-4097-8df2-92f88447063f
“spring:session:sessions:” + sessionId
hash结构有key和field,如上面的例子:hash的key为"spring:session:sessions"前缀加上fc454e71-c540-4097-8df2-92f88447063f,该key下的field有:
- field=sessionAttr:key1,value=… //往session 设置的属性
- field=sessionAttr:key2,value=… //往session 设置的属性根据实际情况可能会有多个
- field=creationTime,value= //创建时间
- field=maxInactiveInterval,value= //最大生存时间
- field=lastAccessedTime,value= //最后访问时间
第二组:String结构,用于ttl过期时间记录
spring:session:sessions:expires:fc454e71-c540-4097-8df2-92f88447063f
key为“spring:session:sessions:expires:”前缀+fc454e71-c540-4097-8df2-92f88447063f
value为空
第三组:set结构,过期时间记录
spring:session:expirations:1515135000000
set的key固定为“spring:session:expirations:1515135000000”,set的集合values为:
- expires:c7fc28d7-5ae2-4077-bff2-5b2df6de11d8 //(一个会话一条)
- expires:fc454e71-c540-4097-8df2-92f88447063f //(一个会话一条)
简单提一下:redis清除过期key的行为是一个异步行为且是一个低优先级的行为,用文档中的原话来说便是,可能会导致session不被清除。于是引入了专门的expiresKey,来专门负责session的清除,包括我们自己在使用redis时也需要关注这一点。在开发层面,我们仅仅需要关注第三个key就行了。
数据获取
在一定场景下,我们需要根据获取到的sessionId来从redis中取到session中保存的数据,一下两种方式
Redis Client
redis client方式直接获取
String sessionId = "spring:session:sessions:7002b5c0-3ae5-487a-873b-5838a4487ba3";
Map<String, String> sessions = jedis.hgetAll(sessionId);
Set<String> entrySet = sessions.keySet();
JdkSerializationRedisSerializer jdk = new JdkSerializationRedisSerializer();
for (String key : entrySet) {
byte bytes[] = jedis.hget(sessionId.getBytes() , key.getBytes());
Object value = jdk.deserialize(bytes);
System.out.println(value.getClass() + "--" + key + "--" + value);
}
RedisTemplate
通过spring 提供的redisTemplate来获取,
配置
在configuration中配置redisSessionTemplate,注意几个Serializer的配置,不匹配会导致读取出错
@Bean
public <K,V> RedisTemplate<K, V> redisSessionTemplate(RedisConnectionFactory factory) {
RedisTemplate<K, V> template = new RedisTemplate<>();
// 配置连接工厂
template.setConnectionFactory(factory);
//JdkSerializationRedisSerializer jdkRedisSerializer = new JdkSerializationRedisSerializer();
RedisSerializer<String> keySerializer = new StringRedisSerializer();
RedisSerializer<Object> valueSerializer = new JdkSerializationRedisSerializer(
this.getClass().getClassLoader());
// 值采用json序列化
template.setValueSerializer(valueSerializer);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(keySerializer);
// 设置hash key 和value序列化模式
template.setHashKeySerializer(keySerializer);
template.setHashValueSerializer(valueSerializer);
template.afterPropertiesSet();
return template;
}
获取
String sessionKey ="spring:session:sessions:" + sessionId;
redisSessionTemplate.opsForHash().get(sessionKey, "sessionAttr:currentUser");
redisSessionTemplate.opsForHash().get(sessionKey, "sessionAttr:loginAccount");