您的当前位置:首页正文

SpringBoot 整合SpringSession 采用redis存储流程、SpringSession原理

2024-11-28 来源:个人技术集锦

缘由

因为在做一个分布式应用框架项目的时候碰到了session问题,我写这篇文章也是自己做一个笔记,也加深一下整合流程的记忆,写的不是很好大佬忽喷
我这里选用的版本号是2021.2.3也就是对应Springboot框架的2.7版本的把因该在,下面也会给出官方资料,免得各位兄弟再去找资料了

资源

首先我先给出官方文档
这个是我们主要看的两个官方文档:
这个是使用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会话信息

接下来我们接着处理

@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 进去看看里面有些啥玩意

  • 第一个初始化用的,里面放了一个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的模式去看看这个怎么实现的,记录的不是很好,请大家多多指教

显示全文