文章目录
1. 前言
关于session共享的方式有多种
-
通过nginx的ip_hash,根据ip将请求分配到对应的服务器
-
基于cookie存储
-
服务器内置的session复制域
-
基于关系型数据库存储(Spring Session JDBC)
-
基于nosql(MemCache、MongoDB(Spring Session MongoDB)、Redis (Spring Session Data Redis)都可以)
常用的就是1和5,下面研究第5种方式,基于nosql(Redis)存储session。
其实实现原理也比较简单,在所有的请求之前配置一过滤器,在请求之前操作session,其实spring-session
中真正起作用的session过滤器是:SessionRepositoryFilter
。spring-session
集成了redis与mongodb等nosql。
有兴趣的可以debug跟进源码看看
2. 代码实现
2.1 添加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
完整pom.xml文件
<?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>
<groupId>top.theonly.spring.session</groupId>
<artifactId>spring-boot-session-redis-test</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/>
</parent>
<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-data-redis</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.2 SpringBoot启动类
@SpringBootApplication
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600) //增加redis session缓存支持
public class SpringSessionApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSessionApplication.class, args);
}
}
@EnableRedisHttpSession
:
该注解创建一个名为“springSessionRepositoryFilter
”并实现了Filter
的Spring Bean(过滤器),该过滤器负责替将HttpSession
替换为 Spring Session支持的实现; 在此,Spring Session由Redis支持。maxInactiveIntervalInSeconds
:设置session的过期时间,默认为1800秒,即30分钟
对于SpringSession是如何将HttpSession替换为SpringSession支持的,可以查看该博客Spring Session 源码分析(1)——springSessionRepositoryFilter
2.3 配置文件application.properties
# 分别启动两个服务,一个来设置session,一个来获取session
server.port=10001
# server.port=10002
server.servlet.context-path=/
# session 存储类型。
spring.session.store-type = redis
# session 超时。如果未指定持续时间后缀,则使用秒。
server.servlet.session.timeout=5
# session 刷新模式。
spring.session.redis.flush-mode=on_save
# 用于存储session 的键的命名空间。
spring.session.redis.namespace=spring:session
#Redis服务器主机。
spring.redis.host=localhost
#Redis服务器的登录密码。
spring.redis.password=
#Redis服务器端口。
spring.redis.port=6379
2.4 controller
/**
* session共享测试controller
* 启动两个服务,端口为10001的服务设置session,端口为10002的服务来获取session,测试是否能够获取,实现session共享
*/
@RestController
@RequestMapping("/session")
public class SessionController {
@Value("${server.port}")
private Integer port;
/**
* 设置session
* redis中的key有一下几个:
* (hash)(session存储) spring:session:sessions:c072782b-28c6-4ca3-9122-d1a3ef21ad89
* (string) spring:session:sessions:expires:c072782b-28c6-4ca3-9122-d1a3ef21ad89
* (set) spring:session:expirations:1603177440000
* @param session
* @return
*/
@PostMapping("/set")
public String set(HttpSession session) {
session.setAttribute("username", "test");
return String.valueOf(port);
}
/**
* 获取session
* @param session
* @return
*/
@GetMapping("/get")
public String get(HttpSession session) {
String username = (String) session.getAttribute("username");
return username + ":" + port;
}
}
3. 启动测试
3.1 启动
分别启动端口为10001和10002的两个服务,用来设置和获取session
注意:修改配置文件的端口后再启动
3.2 测试
- 使用Postman 访问10001端口来设置Session
- 查看Redis
- 分别访问10001和10002端口获取Session
4. 源码