暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Spring Redis Session 存储结构及获取

码路生活 2020-09-07
647

背景

常用的微服务架构如下图,在多个服务实例中需要获取到相同的session


Spring Redis Session 作为分布式共享Session的一种解决方案,现在已经被广泛的应用,项目的搭建这里不做介绍,主要看一看session 的在redis中的存储结构,为之后在RPC调用中传递session做准备


Redis中的存储结构

运行项目后,请求一次接口,进入redis中可以看到,多出来3组数据

Redis中的存储说明:

1、spring:session是默认的Redis HttpSession前缀(redis中,我们常用’:’作为分割符)。

2、每一个session都会创建3组数据

第一组:hash结构,spring-session存储的主要内容 

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结构,过期时间记录



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");



文章转载自码路生活,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论