目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

分布式环境中如何解决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

作者:Soulboy