这篇文章是松哥的原创,可是在第一次发布的时候,忘了标记原创,结果被好多号转发,致使我后来整理的时候本身无法标记原创了。写了几百篇原创技术干货了,有一两篇忘记标记原创进而形成的一点点小小损失也能接受,不过仍是要和小伙伴们说明一下。html
在传统的单服务架构中,通常来讲,只有一个服务器,那么不存在 Session 共享问题,可是在分布式/集群项目中,Session 共享则是一个必须面对的问题,先看一个简单的架构图:java
在这样的架构中,会出现一些单服务中不存在的问题,例如客户端发起一个请求,这个请求到达 Nginx 上以后,被 Nginx 转发到 Tomcat A 上,而后在 Tomcat A 上往 session 中保存了一份数据,下次又来一个请求,这个请求被转发到 Tomcat B 上,此时再去 Session 中获取数据,发现没有以前的数据。对于这一类问题的解决,思路很简单,就是将各个服务之间须要共享的数据,保存到一个公共的地方(主流方案就是 Redis):nginx
当全部 Tomcat 须要往 Session 中写数据时,都往 Redis 中写,当全部 Tomcat 须要读数据时,都从 Redis 中读。这样,不一样的服务就可使用相同的 Session 数据了。git
这样的方案,能够由开发者手动实现,即手动往 Redis 中存储数据,手动从 Redis 中读取数据,至关于使用一些 Redis 客户端工具来实现这样的功能,毫无疑问,手动实现工做量仍是蛮大的。github
一个简化的方案就是使用 Spring Session 来实现这一功能,Spring Session 就是使用 Spring 中的代理过滤器,将全部的 Session 操做拦截下来,自动的将数据 同步到 Redis 中,或者自动的从 Redis 中读取数据。web
对于开发者来讲,全部关于 Session 同步的操做都是透明的,开发者使用 Spring Session,一旦配置完成后,具体的用法就像使用一个普通的 Session 同样。redis
首先 建立一个 Spring Boot 工程,引入 Web、Spring Session 以及 Redis:spring
建立成功以后,pom.xml 文件以下:服务器
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> </dependencies>
注意:session
这里我使用的 Spring Boot 版本是 2.1.4 ,若是使用当前最新版 Spring Boot2.1.5 的话,除了上面这些依赖以外,须要额外添加 Spring Security 依赖(其余操做不受影响,仅仅只是多了一个依赖,固然也多了 Spring Security 的一些默认认证流程)。
spring.redis.host=192.168.66.128 spring.redis.port=6379 spring.redis.password=123 spring.redis.database=0
这里的 Redis ,我虽然配置了四行,可是考虑到端口默认就是 6379 ,database 默认就是 0,因此真正要配置的,其实就是两行。
配置完成后 ,就可使用 Spring Session 了,其实就是使用普通的 HttpSession ,其余的 Session 同步到 Redis 等操做,框架已经自动帮你完成了:
@RestController public class HelloController { @Value("${server.port}") Integer port; @GetMapping("/set") public String set(HttpSession session) { session.setAttribute("user", "javaboy"); return String.valueOf(port); } @GetMapping("/get") public String get(HttpSession session) { return session.getAttribute("user") + ":" + port; } }
考虑到一会 Spring Boot 将以集群的方式启动 ,为了获取每个请求究竟是哪个 Spring Boot 提供的服务,须要在每次请求时返回当前服务的端口号,所以这里我注入了 server.port 。
接下来 ,项目打包:
打包以后,启动项目的两个实例:
java -jar sessionshare-0.0.1-SNAPSHOT.jar --server.port=8080 java -jar sessionshare-0.0.1-SNAPSHOT.jar --server.port=8081
而后先访问 localhost:8080/set
向 8080
这个服务的 Session
中保存一个变量,访问完成后,数据就已经自动同步到 Redis
中 了 :
而后,再调用 localhost:8081/get
接口,就能够获取到 8080
服务的 session
中的数据:
此时关于 session 共享的配置就已经所有完成了,session 共享的效果咱们已经看到了,可是每次访问都是我本身手动切换服务实例,所以,接下来咱们来引入 Nginx ,实现服务实例自动切换。
很简单,进入 Nginx 的安装目录的 conf 目录下(默认是在 /usr/local/nginx/conf
),编辑 nginx.conf 文件:
在这段配置中:
/
表示拦截到全部的请求,转发转发到刚刚配置好的服务集群中配置完成后,将本地的 Spring Boot 打包好的 jar 上传到 Linux ,而后在 Linux 上分别启动两个 Spring Boot 实例:
nohup java -jar sessionshare-0.0.1-SNAPSHOT.jar --server.port=8080 & nohup java -jar sessionshare-0.0.1-SNAPSHOT.jar --server.port=8081 &
其中
配置完成后,重启 Nginx:
/usr/local/nginx/sbin/nginx -s reload
Nginx 启动成功后,咱们首先手动清除 Redis 上的数据,而后访问 192.168.66.128/set
表示向 session
中保存数据,这个请求首先会到达 Nginx
上,再由 Nginx
转发给某一个 Spring Boot
实例:
如上,表示端口为 8081
的 Spring Boot
处理了这个 /set
请求,再访问 /get
请求:
能够看到,/get
请求是被端口为 8080 的服务所处理的。
本文主要向你们介绍了 Spring Session 的使用,另外也涉及到一些 Nginx 的使用 ,虽然本文较长,可是实际上 Spring Session 的配置没啥。
咱们写了一些代码,也作了一些配置,可是全都和 Spring Session 无关,配置是配置 Redis,代码就是普通的 HttpSession,和 Spring Session 没有任何关系!
惟一和 Spring Session 相关的,可能就是我在一开始引入了 Spring Session 的依赖吧!
若是你们没有在 SSM 架构中用过 Spring Session ,可能不太好理解咱们在 Spring Boot 中使用 Spring Session 有多么方便,由于在 SSM 架构中,Spring Session 的使用要配置三个地方 ,一个是 web.xml 配置代理过滤器,而后在 Spring 容器中配置 Redis,最后再配置 Spring Session,步骤仍是有些繁琐的,而 Spring Boot 中直接帮咱们省去了这些繁琐的步骤!不用再去配置 Spring Session。
好了 ,本文就说到这里,本文相关案例我已经上传到 GitHub ,你们能够自行下载:https://github.com/lenve/javaboy-code-samples
原文出处:https://www.cnblogs.com/lenve/p/11987428.html