文章目录
- 引言
- 1. 分布式Session的问题
- 2. 解决方案
- 3. spring-session
- 4. 测试
- 总结
引言
本文主要解决分布式Session的问题。
1. 分布式Session的问题
1.首先在「果然新鲜电商」项目里复制一个portal-web
,并修改端口号为8081
,模拟门户集群,如下图:
2.项目新增controller,作为验证:
package com.guoranxinxian.web.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;
public class TestSessionController {
("${server.port}")
private Integer projectPort;// 项目端口
("/createSession")
public String createSession(HttpSession session, String name) {
session.setAttribute("name", name);
return "当前项目端口->" + projectPort + " sessionId->" + session.getId() + "在Session中存入成功!";
}
("/getSession")
public String getSession(HttpSession session) {
return "当前项目端口->" + projectPort + " sessionId->" + session.getId() + " 姓名->" + session.getAttribute("name");
}
}
3.Nginx负载均衡配置:
#user nobody;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream backServer{
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
server {
listen 8099;
server_name 127.0.0.1;
location / {
proxy_pass http://backServer;
index index.html index.htm;
}
}
}
4.浏览器请求获取session,浏览器请求http://127.0.0.1:8099/getSession
:
请求一次
请求二次
可以看到两次Session的id不一致,并不是我们想要的。那该如何解决呢?下面来讲解决方案。
2. 解决方案
解决方案有如下几种:
- 使用cookie来完成(缺点:不安全,操作不可靠)
- 使用Nginx中的ip绑定策略,同一个ip只能在指定的同一个机器访问(缺点:不支持负载均衡)
- 利用数据库同步session(缺点:效率不高)
- 使用tomcat内置的session同步(缺点:同步可能会产生延迟)
- 使用token代替session(已经有很好的解决方案了,使用spring-session)
- 我们使用spring-session以及集成好的解决方案,存放在redis中(推荐)。
3. spring-session
step1:首先引入spring-session的maven依赖:
<!--spring session 与redis应用基本环境配置,需要开启redis后才可以使用,不然启动Spring boot会报错 -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
step2:配置Redis:
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.jedis.pool.max-idle=100
spring.redis.jedis.pool.min-idle=1
spring.redis.jedis.pool.max-active=1000
spring.redis.jedis.pool.max-wait=-1
step3: 启动类声明允许使用Session共享:
package com.guoranxinxian;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
(exclude = {DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
//maxInactiveIntervalInSeconds为SpringSession的过期时间(单位:秒)
(maxInactiveIntervalInSeconds = 1800)
public class AppPortalWeb {
public static void main(String[] args) {
SpringApplication.run(AppPortalWeb.class, args);
}
}
4. 测试
启动项目:
首先浏览器创建session并设置内容到session:http://127.0.0.1:8099/createSession?name=bruce
浏览器请求:http://127.0.0.1:8099/getSession
,可以看到两次的sessionid
均为:e9f48e08-9099-4472-adeb-bf34b3008004
打开Redis,可以看到redis已经保存了相关的redis的值:
总结
本文主要讲解分布式环境下,使用spring-session解决session共享的问题。