分布式环境中如何解决Session的问题
常见的会话解决方案
- 粘性会话 : Sticky Session (任意节点故障引发请求重定向到其他节点的无法获取到原有 Session)
- 会话复制 : Session Replication (复制成本递增)
- 集中会话 : Centralized Session
Spring Session
- 简化集群中的用户会话管理
- 无需绑定容器特定解决方案
支持的存储
- Redis
- MongoDB
- JDBC
- Hazelcast
实现原理
通过定制的 HttpServletRequest 返回定制的 HttpSession。
- SessionRepositoryRequestWrapper
- SessionRepositoryFilter
- DelegatingFilterProxy
基于 Redis 的 HttpSession
基本配置
- @EnableRedisHttpSession
- 提供 RedisConnectionFactory
- 实现 AbstractHttpSessionApplicationInitializer
SpringBoot 对 Spring Session 的支持
引入依赖
1<?xml version="1.0" encoding="UTF-8"?>
2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4 <modelVersion>4.0.0</modelVersion>
5 <parent>
6 <groupId>org.springframework.boot</groupId>
7 <artifactId>spring-boot-starter-parent</artifactId>
8 <version>2.1.3.RELEASE</version>
9 <relativePath/> <!-- lookup parent from repository -->
10 </parent>
11 <groupId>geektime.spring.web</groupId>
12 <artifactId>session-demo</artifactId>
13 <version>0.0.1-SNAPSHOT</version>
14 <name>session-demo</name>
15 <description>Demo project for Spring Boot</description>
16
17 <properties>
18 <java.version>1.8</java.version>
19 </properties>
20
21 <dependencies>
22 <dependency>
23 <groupId>org.springframework.boot</groupId>
24 <artifactId>spring-boot-starter-web</artifactId>
25 </dependency>
26
27 <dependency>
28 <groupId>org.springframework.boot</groupId>
29 <artifactId>spring-boot-starter-data-redis</artifactId>
30 </dependency>
31 <dependency>
32 <groupId>org.springframework.session</groupId>
33 <artifactId>spring-session-core</artifactId>
34 </dependency>
35 <dependency>
36 <groupId>org.springframework.session</groupId>
37 <artifactId>spring-session-data-redis</artifactId>
38 </dependency>
39
40 <dependency>
41 <groupId>org.springframework.boot</groupId>
42 <artifactId>spring-boot-starter-test</artifactId>
43 <scope>test</scope>
44 </dependency>
45 </dependencies>
46
47 <build>
48 <plugins>
49 <plugin>
50 <groupId>org.springframework.boot</groupId>
51 <artifactId>spring-boot-maven-plugin</artifactId>
52 </plugin>
53 </plugins>
54 </build>
55</project>
application.properties
1spring.redis.host=localhost
SessionDemoApplication
1package geektime.spring.web.session;
2
3import org.springframework.boot.SpringApplication;
4import org.springframework.boot.autoconfigure.SpringBootApplication;
5import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
6import org.springframework.web.bind.annotation.RequestMapping;
7import org.springframework.web.bind.annotation.RestController;
8
9import javax.servlet.http.HttpSession;
10
11@SpringBootApplication
12@RestController
13@EnableRedisHttpSession
14public class SessionDemoApplication {
15
16 public static void main(String[] args) {
17 SpringApplication.run(SessionDemoApplication.class, args);
18 }
19
20 @RequestMapping("/hello")
21 public String printSession(HttpSession session, String name) {
22 String storedName = (String) session.getAttribute("name");
23 if (storedName == null) {
24 session.setAttribute("name", name);
25 storedName = name;
26 }
27 return "hello " + storedName;
28 }
29}
测试
1localhost:8080/hello?name=spring
2hello spring
3
4//重启进程(模拟单机会话丢失),印证会话保存在redis中
5//客户端每次访问会携带Cookie中的 Session_ID
6localhost:8080/hello?name=xx
7hello spring