简介
类似于锁, session这种有状态的东西在单个服务下很灵光, 但是在分布式情景下无力. session的这种登录让服务器变得有状态, 这时使多台服务器具有同样的状态, 就会很艰难.
今天redis中间件可以用来充当服务器的session容器.
Session登录回顾
咱们可以发现, 普通的Session模型很难进行跨服务器的共享.
哪怕是在同一个服务器下的微服务, 你复制多套session, 也可能会出现数据不一致的问题.
解决方案
-
Session复制: 这个是Tomcat原生支持的方案, 但是容易占据网络带宽. 并且每个Tomcat保持全量的session拷贝, 当Tomcat多了, 就很浪费空间.
-
客户端存储: 用户Cookie保存登录状态. 垃圾, 浪费带宽, cookie还有长度限制, cookie还能被篡改窃取. 根本不能用这个方案.
-
Hash一致性: 更改nginx配置, 不需要修改应用代码. 只是服务器重启后会导致session丢失, 并且如果服务进行了水平扩展, rehash session后, 有些用户可能路由不到正确session.
-
找个第三方统一存储: 比如使用数据库或者redis中间件. 就是引入中间件降低系统整体可靠性, 还多了远程调用开销. 统一存储还要注意下session作用域的问题.
其实Spring Session with Redis是个统一存储的解决方案.
Spring Session with Redis
- 引入依赖:
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
- 配置
spring.session.store-type=redis
还有些自己查手册, 比如session超时时间等等.
也可写配置类
@Configuration
public class GulimallSessionConfig {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
//放大作用域
cookieSerializer.setDomainName("demo.com");
cookieSerializer.setCookieName("DEMOSESSION");
return cookieSerializer;
}
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
}
- 业务代码
程序入口:
@EnableRedisHttpSession //整合Redis作为session存储
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class GulimallAuthServerApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallAuthServerApplication.class, args);
}
}
然后其他的session相关代码正常写就行, 比如:
@GetMapping(value = "/login.html")
public String loginPage(HttpSession session) {
//从session先取出来用户的信息,判断用户是否已经登录过了
Object attribute = session.getAttribute(LOGIN_USER);
//如果用户没登录那就跳转到登录页面
if (attribute == null) {
return "login";
} else {
return "redirect:http://demo.com";
}
}
spring session作用域问题
@Configuration
public class GulimallSessionConfig {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
//放大作用域
cookieSerializer.setDomainName("demo.com");
cookieSerializer.setCookieName("DEMOSESSION");
return cookieSerializer;
}
}
spring session JSON序列化
@Configuration
public class GulimallSessionConfig {
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
}