目录

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 的支持

引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.3.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>geektime.spring.web</groupId>
	<artifactId>session-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>session-demo</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.session</groupId>
			<artifactId>spring-session-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.session</groupId>
			<artifactId>spring-session-data-redis</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

application.properties

spring.redis.host=localhost

SessionDemoApplication

package geektime.spring.web.session;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

@SpringBootApplication
@RestController
@EnableRedisHttpSession
public class SessionDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(SessionDemoApplication.class, args);
	}

	@RequestMapping("/hello")
	public String printSession(HttpSession session, String name) {
		String storedName = (String) session.getAttribute("name");
		if (storedName == null) {
			session.setAttribute("name", name);
			storedName = name;
		}
		return "hello " + storedName;
	}
}

测试

localhost:8080/hello?name=spring
hello spring

//重启进程(模拟单机会话丢失),印证会话保存在redis中
//客户端每次访问会携带Cookie中的 Session_ID
localhost:8080/hello?name=xx
hello spring

作者:Soulboy