缘由
因为在做一个分布式应用框架项目的时候碰到了session问题,我写这篇文章也是自己做一个笔记,也加深一下整合流程的记忆,写的不是很好大佬忽喷
我这里选用的版本号是2021.2.3
也就是对应Springboot框架的2.7
版本的把因该在,下面也会给出官方资料,免得各位兄弟再去找资料了
资源
首先我先给出官方文档SpringSession
这个是我们主要看的两个官方文档:
这个是使用redis作为存储的官方文档SpringSession with redis
这个是我们使用redis序列化机制的时候看的Demo,这个实在github上面示例代码我们可以直接那这个示例代码过来照抄
开始操作,开干 ~~
首先我们要去引入相应的依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.10</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!--你们只需要复制下面两个依赖就行了-->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
引入依赖之后我们要去配置文件里面配置相关信息
spring.session.store-type=redis # 会话存储类型。
server.servlet.session.timeout=30m # 超时时间,默认30分钟
# spring.session.redis.flush-mode=on_save # 会话刷新模式
# spring.session.redis.namespace=spring:session # 命名空间也是默认的
# 因为我们是采用redis作为存储的所以我们也需要去配置相关redis信息
spring.redis.host=localhost # Redis server host.
spring.redis.password= # Login password of the redis server.
spring.redis.port=6379 # Redis server port.
最后我们需要在我们的启动类上面添加一个注解,启用redis session
@EnableRedisHttpSession
我们可以把这个注解配置的我们后面说的配置类中,看个人习惯
到目前这样我们在单体项目里面整合SpringSession就整合成功了,但是这里的存储在redis中的内容是采用jdk的序列化机制,但是到了这里,如果我们是多个域名下面访问的话,还是会出问题,父域访问不到子域的session会话信息
接下来我们接着处理
我们需要添加一个配置类,类配置相关信息提升作用域以及redis的序列化机制,下面是官方地址
https://github.com/spring-projects/spring-session/tree/2.7.4/spring-session-samples/spring-session-sample-boot-redis-json
@Configuration
public class MallSessionConfig {
/**
* description 提升作用域
* @return org.springframework.session.web.http.CookieSerializer
* @author 沐光
*/
@Bean
public CookieSerializer cookieSerializer(){
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
cookieSerializer.setDomainName("你的父域名");
cookieSerializer.setCookieName("你的session名字");
return cookieSerializer;
}
/**
* description 配置redis的序列化器
* @return org.springframework.data.redis.serializer.RedisSerializer<java.lang.Object>
* @author 沐光
*/
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer(){
return new GenericJackson2JsonRedisSerializer();
}
}
注意 :这样的话我们需要在我们使用的分布式session的服务中都要去配置这写相关配置,不然会不起作用
各位大佬,这个简单的整合到这里就结束了。
工作流程
当然这里也都是我自己的理解,说的不是很好,把上面的看了,就能正常使用了
我们先从他在启动类上面引入的注解@EnableRedisHttpSession
,点进去看看他给我们做了一些什么事情
- 在这里我们看到他给我们导入了一个配置类
RedisHttpSessionConfiguration
我们再去这个配置类里面看看有些啥玩意
- 首先他给我们继承了一个
SpringHttpSessionConfiguration
配置类
- 我们接着往下面看,他给我们注入了一个bean
RedisIndexedSessionRepository
我们先去看一下这个注入的Bean里面做了一些啥事情
- 我们看到这个Bean里面的结构都是一些对redis的操作,到这里我们是不是可以得出一个结论,这个Bean组件就是redis 操作session的CURD的
我们接着回到上面的这个
RedisHttpSessionConfiguration
这配置里面看看结构
- 里面有一个监听器
RedisMessageListenerContainer
这个好像是连接redis工厂使用的 - 这里我就不做过多的赘述了
我们现在回到上面说的那个继承的类中
SpringHttpSessionConfiguration
进去看看里面有些啥玩意
我们看到这个里面里面有这三个Bean组件看看使用来干嘛的
- 第一个初始化用的,里面放了一个CookieSerializer 序列化用的,我们之前的配置里面我们配置了一个序列化用的
- 第二个SessionEventHttpSessionListenerAdapter 这个是一个会话事件Http会话侦听器适配器,监听事件用的,我们暂时不管
- 最重要的我们是看这个Bean
SessionRepositoryFilter
这个好像是一个过滤器,接下我们去瞅瞅这个里面
SessionRepositoryFilter 从下面这张图里面看出来他继承了OncePerRequestFilter这个抽象类,从下一张图片看出它实现了我们的Filter接口,现在确定了他就是一个过滤器,我们看看他这里做了一些啥
SessionRepositoryFilter 他这个里面只有一个构造方法 需要一个SessionRepository这个类型的参数,到这里我们是不是想到一点啥了,我们在之前的 RedisIndexedSessionRepository这个组件中获取到这个
我们先接着往下面看,这段代码,重大发现他把我们的原生的过滤器进行封装 装饰了
wrappedRequest成这个了
所有我们后面的获取dsession
wrappedRequest.getSession() --> 从SessionRepository这个里面获取到
所以我们看到的这下面这段代码就是这个SpringSession的核心代码
装饰者模式
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);
SessionRepositoryFilter<S>.SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryFilter.SessionRepositoryRequestWrapper(request, response);
SessionRepositoryFilter.SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryFilter.SessionRepositoryResponseWrapper(wrappedRequest, response);
try {
filterChain.doFilter(wrappedRequest, wrappedResponse);
} finally {
wrappedRequest.commitSession();
}
}
SessionRepository
到这里我们查看了SpringSession的底层代码,他就是一层一层的嵌套查找获取到我们想要的东西,最后把原生的过滤器进行封装。
最后,我在这里粗滤的浅谈了一下这个SpringSession的工作流程,感兴趣的朋友可以自己通过Dbug的模式去看看这个怎么实现的,记录的不是很好,请大家多多指教