1.前言
最近技术总监在群里问个问题,我比较在意就是如何把spring session做成多机会话共享(集群)
主要遇到情况例如:
一个用户登录成功之后,然后去访问一个查询接口突然就宕机了,怎么办,就算你做了负载均衡但是你当前一个会话丢失了,用户还需要重新登录,很影响用户的体验。
这里就要说到我们技术总监说的问题,Spring Session作为多机会话共享的问题:
先解释一下Session的本质是什么?
1.设置一个生命周期
2.浏览器登录时根据生成的token保存session
3.在过期前同一个浏览器共享那个session里面所有的内容
通俗易懂的解释就是一次会话
我们在看看SessionID的本质?
通俗易懂的解释,确定用户是在同一会话,就是确定这个用户。
这里在正式解释一下为何Spring Session作为多机会话共享可以解决用户重新登录问题:
Session存储的在内存当中,所以一但服务器挂了,内存里面东西就会丢失,但是通过Spring Session可以通过一个配置类创建一个过滤器,这个过滤器支持Spring Session代替HttpSession发挥作用,这样就可以把session存放在redis缓存当中,不至于服务器挂了,你的Session会话就丢失,也可以实现多台服务器共享这个会话,只要你的那些服务器用的是同一redis。
2.依赖
<?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>SpringSession</groupId>
<artifactId>SpringSession</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring session -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.3.0.RELEASE</version>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
<!-- servlet 依赖. -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!-- tomcat 的支持.-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>SpringSession</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin </artifactId>
</plugin>
</plugins>
</build>
</project>
3.这个配置类可以创建一个过滤器,这个过滤器支持Spring Session代替HttpSession发挥作用。
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
@EnableRedisHttpSession
public class HttpSessionConfig {
@Bean
public JedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory();
}
}
4.Controller层:
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class UserController {
@RequestMapping(value="/main", method=RequestMethod.GET)
public String main(HttpServletRequest request) {
HttpSession session = request.getSession();
String sessionId = (String) session.getAttribute("sessionId");
if (null != sessionId) { // sessionId不为空
System.out.println("main sessionId:" + sessionId);
return "main";
} else { // sessionId为空
return "redirect:/login";
}
}
@RequestMapping(value="/login", method=RequestMethod.GET)
public String login() {
return "login";
}
@RequestMapping(value="/doLogin", method=RequestMethod.GET)
public String doLogin(HttpServletRequest request) {
System.out.println("我在这里登陆");
HttpSession session = request.getSession();
String sessionId = UUID.randomUUID().toString();
session.setAttribute("sessionId", sessionId);
System.out.println("login sessionId:" + sessionId);
return "redirect:/main";
}
}
4.在 src/main 下面创建 webapp/WEB-INF/jsp 目录用来存放我们的jsp页面:login.jsp,main.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
helloJsp
<hr>
${hello}
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
this is main
<hr>
${hello}
</body>
</html>
5.application.properties配置类
# 页面默认前缀目录
spring.mvc.view.prefix=/WEB-INF/jsp/
# 响应页面默认后缀
spring.mvc.view.suffix=.jsp
# 自定义属性,可以在Controller中读取
application.hello=Hello Angel From application
# REDIS (RedisProperties)
spring.redis.database=0
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
spring.redis.jedis.timeout=0
6.测试
你访问http://localhost:8080/main
然后去redis查询如图:
访问的页面,存储到redis里面
这里就成功把Session存储到redis里面,其实这里只是Spring Session来做多机会话共享一,后期我会把服务器部署多机会话写出来,请关注我。
指导qq:179061434
参考demo:链接: https://pan.baidu.com/s/1T-5KIES7pTmE3xViY-DeIw 密码: 874g
网友评论