1. 功能描述

提供开箱即用的集中式用户session管理, 从而不需要依赖web应用容器.

2. 使用

2.1. 引入依赖

pom.xml
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-launcher</artifactId>
        </dependency>

2.2. 添加session配置

application.yml
spring:
    application:
        name: session-demo
    session:
        store-type: redis
logging:
    level:
        org.springframework.session: debug

2.3. 设置token位置为header(Optional)

SessionConfiguration.java
@Configuration
public class SessionConfiguration {

    @Bean
    public HttpSessionIdResolver sessionIdResolver() {
        return HeaderHttpSessionIdResolver.xAuthToken();
    }

    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
        return new GenericJackson2JsonRedisSerializer();
    }
}

2.4. 写个接口

DemoController.java
@RestController
public class DemoController {

    @GetMapping("/")
    public String index(@Value("${spring.application.name}") String name, HttpSession session) {
        return name;
    }
}

2.5. 测试一下

DemoControllerTests.java
@SpringBootTest(classes = SessionDemoApplication.class)
@AutoConfigureMockMvc
class DemoControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Value("${spring.application.name}")
    private String applicationName;

    @Test
    void testSessionHeader() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/"))
            .andDo(MockMvcResultHandlers.log())
            .andExpect(MockMvcResultMatchers.status().isOk())
            .andExpect(MockMvcResultMatchers.content().string(applicationName))
            .andExpect(MockMvcResultMatchers.header().exists("X-Auth-Token"))
            .andReturn();
    }
}

3. 核心类

3.1. Session

标识同一个session(user).

主要实现类
  • MapSession: 一些基本的属性: id/originalId/attrs/creationTime/lastAccessedTime .

  • RedisSession: session attribute修改时内部会同步修改redis中的值.

3.2. SessionRepository

具体操作session.

主要实现类
  • MapSessionRepository: 在内存中维护一个 Map 管理session.

  • FindByIndexNameSessionRepository: 新增根据用户名或者指定key查询session的接口.

  • RedisOperationsSessionRepository: 用 RedisTemplate 管理session.

3.3. SessionRepositoryRequestWrapper

包装 HttpServletRequest , 覆盖 getSession 等方法.

3.4. SessionRepositoryResponseWrapper

包装 HttpServletResponse , 调用部分方法时同步session到Redis中.

3.5. SessionRepositoryFilter

每次请求将 HttpServletRequestHttpServletResponse 分别包装成 SessionRepositoryRequestWrapperSessionRepositoryResponseWrapper .

4. 启动流程

  1. spring.factories 中存在 org.springframework.boot.autoconfigure.session.SessionAutoConfiguration ,自动引入 SessionAutoConfiguration .

  2. SessionAutoConfiguration.ServletSessionConfiguration.ServletSessionRepositoryConfiguration 根据 spring.session.store-typeWebApplicationType 引入不同的SessionConfiguration类, 通常为 RedisSessionConfiguration .

  3. SpringBootRedisHttpSessionConfiguration 配置类装载bean:

    1. RedisOperationsSessionRepository

    2. SessionRepositoryFilter

    3. SessionEventHttpSessionListenerAdapter

    4. RedisMessageListenerContainer

    5. EnableRedisKeyspaceNotificationsInitializer