Spring Session 是 Spring 的项目之一。Spring Session 提供了一套创建和管理 Servlet HttpSession 的方案,默认采用外置的 Redis 来存储 Session 数据,以此来解决 Session 共享的 问题。
搭建案例环境
项目简单介绍,创建了一个父项目,两个聚合模块的子项目 父项目为pom项目 子项目为jar项目
1.创建父项目
创建项目 ,修改pom文件
注 :需要继承SpringBoot父项目的启动器,添加项目运行环境,相关的jar
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.7.RELEASEversion>
<relativePath/>
parent>
<groupId>ah.szxy.springsessiongroupId>
<artifactId>01-SpringSessionartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>pompackaging>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.sessiongroupId>
<artifactId>spring-session-coreartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.sessiongroupId>
<artifactId>spring-session-data-redisartifactId>
dependency>
<dependency>
<groupId>io.lettucegroupId>
<artifactId>lettuce-coreartifactId>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
2.创建两个子项目
session_service1,session_service2
3.测试结果 访问session_service1的controller查看结果
查看redis数据库是否存放了session数据
默认的保存的时间约为2100s
访问session_service2 的controller查看结果
在上面的案例中进行修改
1.两个子模块都添加实体类
因为涉及对象类型数据传输到redis,故需要实现序列化接口
package ah.szxy.domain;
import java.io.Serializable;
public class Users implements Serializable{
private String username;
private String userpwd;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUserpwd() {
return userpwd;
}
public void setUserpwd(String userpwd) {
this.userpwd = userpwd;
}
@Override
public String toString() {
return "Users [username=" + username + ", userpwd=" + userpwd + "]";
}
public Users() {
super();
}
public Users(String username, String userpwd) {
super();
this.username = username;
this.userpwd = userpwd;
}
}
2.子模块1的controller
@RequestMapping("addUser")
public String addUser(HttpSession session,Users user) {
session.setAttribute("user", user);
return "addUser Success!!!";
}
3.测试结果
访问session_service1的controller查看结果 查看redis数据库是否存放了session数据 访问session_service2 的controller查看结果
spring:session:expirations:(Set 结构)
用户 ttl 过期时间记录 , 这个 key中的值是一个时间戳, 根据这个 Session 过期时刻滚动至下一分钟而计算得出。 这个 key 的过期时间为 Session 的最大过期时间 +5 分钟(再此为2100s)。
spring:session:sessions:(Hash 结构) maxInactiveInterval:过期时间间隔 creationTime:创建时间 lastAccessedTime:最后访问时间 sessionAttr:Attributes 中的数据存储 Session 的详细信息,包括 Session 的过期时间间隔、最后的访问时间、attributes 的值。这个 key 的过期时间为 Session 的最大过期时间 +5 分钟。
spring:session:sessions:expires:(String 结构)
过期时间记录 : 这个 k-v 不存储任何有用数据,只是表示 Session 过期而设置。 这个 key 在 Redis 中的过期时间即为 Session 的过期时间间隔
修改启动类的@EnableRedisHttpSession注解
@SpringBootApplication
/**
* 设置超时时限
* 需要两端同步,单位秒
*/
@EnableRedisHttpSession(maxInactiveIntervalInSeconds=20)
@SpringBootApplication
public class SessionServlet1Application {
public static void main(String[] args) {
SpringApplication.run(SessionServlet1Application.class, args);
}
}
点击注解即可进入相应的注解接口 ,可以看到其中有四个属性
属性 | 作用 |
---|---|
maxInactiveIntervalInSeconds | 设置 Session 的失效时间,单位为秒。默认(1800 秒)30 分钟。 |
redisNamespace | 为键定义唯一的命名空间。该值用于通过更改前缀与默认 spring:session 隔离会话 |
redisFlushMode | Redis 会话的刷新模式。默认值为“保存” |
cleanupCron | 过期会话清理作业的 cron 表达式。默认值(“0 *****”)每分钟运行一次。 |
SpringSession 中默认的序列化器为 jdk 序列化器,该序列化器效率低下,内存再用大。 我们可以根据自己的需要更换其他序列化器,如 GenericJackson2JsonRedisSerializer 序列化器。 使用配置类跟换序列器
/**
* 1.需要两端都添加这个配置类
* 2.同时允许关联对象的添加
* @author 曹海洋
*
*/
@Configuration
public class SpringSessionConfig {
/**
* 更换序列化器
* @return
*/
@Bean("springSessionDefaultRedisSerializer")
public RedisSerializer setSerializer(){
return new GenericJackson2JsonRedisSerializer();
}
}
注意 : 1.如果在项目中使用序列化其,建议使用这里推荐的序列化器序列化器的配置类 2.将原来的数据清空 3.不要额外导入jar, 上面添加的坐标包含的jar足够
配置前
配置后
1 什么是Spring Session MongoDB Spring Session MongoDB 是Spring Session 的二级项目。其功能与Spring Session 是相同的。 Spring Session MongoDB 提供了一个API 和实现,用于通过利用Spring Data MongoDB来管理存储在MongoDB 中的用户会话信息。
2 与Spring Session 的区别 Spring Session 与Spring Session MongoDB 的作用是相同的。都是来解决Session 共享问题。 不同的是Spring Session 默认的是依赖于Redis 作为数据缓存平台,而Spring SessionMongoDB 是依赖于MongoDB 来作为数据缓存平台的。
环境搭建
创建一个父项目,两个子项目 父项目为pom项目,规定所用jar版本与种类 子项目为jar项目,实现具体的模拟内容
1.创建父项目,修改pom文件
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.7.RELEASEversion>
<relativePath />
parent>
<groupId>ah.szxy.springSessiongroupId>
<artifactId>02-SpringSession-MongoDBartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>pompackaging>
<properties>
<java.version>1.8java.version>
<maven-jar-plugin.version>3.1.1maven-jar-plugin.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.sessiongroupId>
<artifactId>spring-session-coreartifactId>
dependency>
<dependency>
<groupId>org.springframework.sessiongroupId>
<artifactId>spring-session-data-mongodbartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-mongodbartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
<modules>
<module>session_mongo2module>
modules>
project>
2.创建两个子项目,无需修改pom文件
4.0.0
ah.szxy.springSession
02-SpringSession-MongoDB
0.0.1-SNAPSHOT
session_mongo1
注意:两个pom文件除名称不一样外,其他一致
3.修改全局配置文件 application.yml
server:
port: 8081
spring:
application:
name: Session-Mongdb1
session:
store-type: mongodb
data: #配置MongoDB的连接参数
mongodb:
host: 192.168.179.131
port: 27017
database: chy #自定义MongoDB库名称
注意:两个配置文件处理应用名,端口号不一样外,其他一致
4.启动类
package ah.szxy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession;
@SpringBootApplication
@EnableMongoHttpSession
public class SessionMongoApp {
public static void main(String[] args) {
SpringApplication.run(SessionMongoApp.class, args);
}
}
注:两个启动类完全一致
4.session_mongo1的controller
@RestController
@RequestMapping("service1")
public class MongoDBController {
@RequestMapping("setMsg")
public String showMsg(HttpSession session) {
session.setAttribute("msg", "Hello MongoDB!!!");
return "ok";
}
}
5.session_mongo2的controller
@RestController
@RequestMapping("service2")
public class MongoDBController {
@RequestMapping("getMsg")
public String showMsg(HttpSession session) {
String msg = (String) session.getAttribute("msg");
return msg;
}
}
6.测试结果
启动两个项目, 访问session_mongo1的controller
访问session_mongo2的controller
1.两个子模块都要创建Users实体类
package ah.szxy.domain;
import java.io.Serializable;
public class Users implements Serializable{
private String username;
private String userpwd;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUserpwd() {
return userpwd;
}
public void setUserpwd(String userpwd) {
this.userpwd = userpwd;
}
@Override
public String toString() {
return "Users [username=" + username + ", userpwd=" + userpwd + "]";
}
public Users() {
super();
}
public Users(String username, String userpwd) {
super();
this.username = username;
this.userpwd = userpwd;
}
}
注意:勿忘实现序列化接口
2.session_mongo1的controller中添加方法
@RequestMapping("addUser")
public String showMsg(HttpSession session,Users user) {
session.setAttribute("user", user);
return "ok";
}
3.session_mongo2的controller中添加方法
@RequestMapping("getUser")
public Users showUser(HttpSession session) {
Users user=(Users) session.getAttribute("user");
return user;
}
4.测试结果
使用其专用的查询语句即可查看它的存储结构
整理如下 点击使用json格式校验/转换
{
"_id": "138af2fe-cf3f-4e8d-8ea1-a311ecd70edc",
"created": ISODate("2019-09-16T08:42:51.767Z"),
"accessed": ISODate("2019-09-16T09:07:10.425Z"),
"interval": "PT30M",
"principal": null,
"expireAt": ISODate("2019-09-16T09:37:10.425Z"),
"attr": BinData(0, "rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAACdAADbXNndAAQSGVsbG8gTW9uZ29EQiEhIXQABHVzZXJzcgAUYWguc3p4eS5kb21haW4uVXNlcnOYj4Y/edg3CAIAAkwACHVzZXJuYW1ldAASTGphdmEvbGFuZy9TdHJpbmc7TAAHdXNlcnB3ZHEAfgAGeHB0AANjaHl0AAl0aW1lcGF1c2V4")
}
/**
* @EnableMongoHttpSession
* maxInactiveIntervalInSeconds: 设置超时时限, 两个子模块的这个属性必须一致
* collectionName: 可省略,唯一标识,使用时两个子模块的这个属性必须一致
*/
@SpringBootApplication
@EnableMongoHttpSession(maxInactiveIntervalInSeconds=20,collectionName="test")
public class SessionMongoApp {
public static void main(String[] args) {
SpringApplication.run(SessionMongoApp.class, args);
}
}
注意 : @EnableMongoHttpSession注解的两个属性的用法
属性 | 作用 |
---|---|
maxInactiveIntervalInSeconds | 设置 Session 失效时间 ,默认为2100s |
collectionName | 设置 MongoDB 的 Collections 的名称 ,默认为seesions |
默认使用的是jdk序列化器,序列化后产生的数据较大,占用内存较高,因此最好换成其他的序列化器
@Configuration
public class SerializableConfig {
@Bean
JacksonMongoSessionConverter mongoSessionConverter() {
return new JacksonMongoSessionConverter();
}
}
启动项目时报错,因为json转换时对对象的属性做了校验, 而自定义对象的属性不在白名单中,我们需要关闭属性的自动校验。
@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
public class User implements Serializable {
private String username;
private String userpwd;
...
}
mongodb中存储的数据
{
"_id" : "36d3dd35-e33d-49f8-bde9-ec3587e2d560",
"@class" : "org.springframework.session.data.mongo.MongoSession",
"createdMillis" : NumberLong(1566549133774),
"accessedMillis" : NumberLong(1566549137807),
"intervalSeconds" : 20,
"expireAt" : ISODate("2019-08-23T08:32:37.807Z"),
"attrs" : {
"@class" : "java.util.HashMap",
"user" : {
"@class" : "cn.xyl.pojo.User",
"_id" : 123,
"name" : "hello"
}
},
"principal" : null
}