前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring-data-redis 的实现原理

Spring-data-redis 的实现原理

作者头像
平凡的学生族
发布2019-10-12 16:09:37
1.6K0
发布2019-10-12 16:09:37
举报
文章被收录于专栏:后端技术后端技术

强烈建议阅读Spring-session原理的"2.spring-session重写servlet request 及 redis实现存储相关问题"

另外在写作中,适当参考了下面的文章。它们的分析并不完全符合本文的场景,但都有值得参考之处

  1. https://blog.csdn.net/u010648555/article/details/79491988#2SessionRepositoryFilterFilterChain_201
  2. https://juejin.im/post/5cb4a34f6fb9a0688360fd91#heading-3

1. redis session的作用来源:SessionRepositoryFilter

我们知道,引入spring-data-redis后,request.getSession()的行为将会从redis中寻找,为什么会这样呢?简单来说,这是因为SessionRepositoryFilter被添加到Servlet拦截链,将request和response替换了。 它是这样起作用的:

  1. 该类通过建立Filter,继承SessionRepositoryRequestWrapper和SessionRepositoryResponseWrapper得到两个自定义类
  2. 在拦截链调用前就把Request和Reponse替换为自己的两个自定义类。
  3. 之后的request和response的调用,其行为就会改为在redis中查找

2. SessionRepositoryFilter的生成

SessionRepositoryFilter是如何被生成、加入拦截链的呢? 参考https://zhuanlan.zhihu.com/p/75776430,一切得从@EnableRedisHttpSession讲起:

代码语言:javascript
复制
@Import(RedisHttpSessionConfiguration.class)
@Configuration
public @interface EnableRedisHttpSession {

@EnableRedisHttpSession直接引入了RedisHttpSessionConfiguration。

2.1 RedisHttpSessionConfiguration

看下该类的定义:

代码语言:javascript
复制
@Configuration
@EnableScheduling
public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration ...{
    @Bean
    public RedisOperationsSessionRepository sessionRepository() {
        RedisTemplate<Object, Object> redisTemplate = createRedisTemplate();
        RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(
                redisTemplate);
        ...
        return sessionRepository;
    }

上面两张图暴露两个信息:

  1. RedisHttpSessionConfiguration是SpringHttpSessionConfiguration的子类,后者也会在类里定义一些Bean。
  2. 该类会注册一个RedisOperationsSessionRepository类型的Bean,而根据上图2,该类也是一个SessionRepository。注意,因为这一点,这个Bean将会在之后被注入到其它Bean中。

跟着第一点的思路,我们看下父类SpringHttpSessionConfiguration。生成了SessionRepositoryFilter,我们看下父类:

代码语言:javascript
复制
/**
 * Configures the basics for setting up Spring Session in a web environment. In order to
 * use it, you must provide a {@link SessionRepository}. For example:
  ...
 */
@Configuration
public class SpringHttpSessionConfiguration implements ApplicationContextAware {

  @Bean
  public <S extends Session> SessionRepositoryFilter<? extends Session> springSessionRepositoryFilter(
        SessionRepository<S> sessionRepository) {
      SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<>(
              sessionRepository);
      ...
      return sessionRepositoryFilter;
  }
...

可知,该方法会接受springboot自动注入的SessionRepository<S>为参数,并以此构建SessionRepositoryFilter。而回忆前面提到的,这个参数就是RedisHttpSessionConfiguration中提供的RedisOperationsSessionRepository。

这一章的总结了包含了RedisOperationsSessionRepository的SessionRepositoryFilter,是如何被生成为Bean的。我们之后会提到,这个Bean是如何加入拦截链的

3. SessionRepositoryFilter加入拦截链

首先,spring-boot-autoconfigure里的spring.factories里有提到SessionAutoConfiguration。springboot就会自动加载该类(不知道为什么会自动加载的话,建议先百度springboot自动加载原理)。

image.png

我们看下该类的定义:

代码语言:javascript
复制
@Configuration
...
public class SessionAutoConfiguration {
    ...
    @Import({ ServletSessionRepositoryValidator.class, SessionRepositoryFilterConfiguration.class })
    static class ServletSessionConfiguration {

其中的@Import...导入了SessionRepositoryFilterConfiguration。看下定义:

代码语言:javascript
复制
@Configuration
@ConditionalOnBean(SessionRepositoryFilter.class)
@EnableConfigurationProperties(SessionProperties.class)
class SessionRepositoryFilterConfiguration {

    @Bean
    public FilterRegistrationBean<SessionRepositoryFilter<?>> sessionRepositoryFilterRegistration(
            SessionProperties sessionProperties, SessionRepositoryFilter<?> filter) {  // 接受springboot的注入
        FilterRegistrationBean<SessionRepositoryFilter<?>> registration = new FilterRegistrationBean<>(filter);  // 以filter为参数
        ...
        return registration;
    }

SessionRepositoryFilterConfiguration是一个@Configuration,我们分析下这个类:

  1. 该类有这@ConditionalOnBean(SessionRepositoryFilter.class)标记,说明该类会在SessionRepositoryFilter准备好时才被处理
  2. sessionRepositoryFilterRegistration方法会接受SessionRepositoryFilter类型的自动注入。这个类型的Bean在@EnableRedisHttpSession的作用下已经生成。
  3. sessionRepositoryFilterRegistration方法会生成FilterRegistrationBean这个Bean。这个Bean值得研究。

在此处debug,会得到以下信息,供读者参考:

接下来我们要分析FilterRegistrationBean。

3.1 FilterRegistrationBean

根据Servlet3.0规范,这种Bean会被自动调用onStartup方法。这个方法的行为是把内部的filter注册,而上文提到这里的filter就是SessionRepositoryFilter。

关于Servlet3.0,可参考https://www.cnblogs.com/duanxz/archive/2012/10/25/2738173.html

在spring boot中添加自己的Servlet有两种方法,代码注册Servlet和注解自动注册(Filter和Listener也是如此)。

  1. 代码注册通过ServletRegistrationBean、 FilterRegistrationBean 和 ServletListenerRegistrationBean 获得控制。
  2. 也可以通过实现 ServletContextInitializer 接口直接注册。 在 SpringBootApplication 上使用@ServletComponentScan 注解后,Servlet、Filter、Listener 可以直接通过 @WebServlet、@WebFilter、@WebListener 注解自动注册,无需其他代码。

之后,ServletRegistrationBean::onStartup到底是如何被调用的呢?它内部又是如何注册filter的呢?这就不是本文需要关注的了。我们只需要知道,SessionRepositoryFilter在此会被加入拦截链,而它之后又会在拦截链中替换Request、Response,从而更改Session的行为是查看redis

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.10.10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. redis session的作用来源:SessionRepositoryFilter
  • 2. SessionRepositoryFilter的生成
    • 2.1 RedisHttpSessionConfiguration
    • 3. SessionRepositoryFilter加入拦截链
      • 3.1 FilterRegistrationBean
      相关产品与服务
      云数据库 Redis
      腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档