SpringSesion共享使用、自定義Session作用域
通常情況下,Tomcat、Jetty等Servlet容器,會默認將Session保存在內存中。如果是單個服務器實例的應用,將Session保存在服務器內存中是一個非常好的方案。但是這種方案有一個缺點,就是不利於擴展。
目前越來越多的應用采用分布式部署,用於實現高可用性和負載均衡等。那么問題來了,如果將同一個應用部署在多個服務器上通過負載均衡對外提供訪問,如何實現Session共享?
實際上實現Session共享的方案很多,其中一種常用的就是使用Tomcat、Jetty等服務器提供的Session共享功能,將Session的內容統一存儲在一個數據庫(如MySQL)或緩存(如Redis)中。
下面我們將在springcloud微服務項目中,使用第三方存儲服務保存(redis),但是如果是直接使用redis,要求對我們的代碼進行修改。所以使用spring session。spring session的原理是對我們的request和response進行了包裝。因為session的獲取是request.getSession() ,所以包裝了請求體,而cookie的設置需要設置到response中所以也包裝了響應體。spring session很完美的解決了代碼重構的問題。還能對接不同的存儲中間件,不僅僅限於redis。子域共享問題。自定義cookie的響應信息。設置cookie 的作用域domean 只能是當前域名或者父域名。domean 是子域名可以拿到父域名的信息,domean是父域名不能拿到子域名的信息。
代碼
Sample Applications that use Spring Boot session redis guide
Sample Applications that use Spring Java-based configuration session redis guide
[HttpSession with Redis JSON serialization](https://github.com/spring-projects/spring-session/tree/2.1.12.RELEASE/samples/boot/redis-json)
依賴
<!-- 整合spring session完成session 共享問題 -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置文件
# redis的連接信息
spring.redis.host=192.168.1.10
spring.redis.port=6379
# 將session數據保存到redis中
spring.session.store-type=redis
spring.session.redis.flush-mode=on_save
spring.session.redis.namespace=spring:session
啟用自動配置(啟動類配置 )
@EnableRedisHttpSession // 整合redis作為session存儲,就是通過filter包裝了我們的請求體和響應體
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class GulimallAuthServerApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallAuthServerApplication.class, args);
}
}
Spring sessioin 中redis的序列化、cookie的自定義設置
/**
*
* Description:設置Session作用域、自定義cookie序列化機制
* date:2020/11/5
*/
@Configuration
public class GlMallSessionConfig {
@Bean
public CookieSerializer cookieSerializer(){
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
// 明確的指定Cookie的作用域
cookieSerializer.setDomainName("gulimall.com");
cookieSerializer.setCookieName("FIRESESSION");
return cookieSerializer;
}
/**
* 自定義序列化機制
* 這里方法名必須是:springSessionDefaultRedisSerializer
*/
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer(){
return new GenericJackson2JsonRedisSerializer();
}
}
---存入session(統一存儲到redis,進行服務之間進行共享Session)
@PostMapping("/login")
public String login(UserLoginVo userLoginVo, RedirectAttributes redirectAttributes, HttpSession session){
//遠程登錄
R login = memberFeignService.login(userLoginVo);
if (login.getCode()==0){
//登錄成功
MeberRespVo meberRespVo = login.getData("data", new TypeReference<MeberRespVo>() {
});
//存入session(統一存儲到redis,進行服務之間進行共享Session)
session.setAttribute("loginUser",meberRespVo);
return "redirect:http://gulimall.com";
}else {
HashMap<String, String> errors = new HashMap<>();
errors.put("errors",login.getData("msg",new TypeReference<String>(){}));
redirectAttributes.addFlashAttribute("errors",errors);
return "redirect:http://auth.gulimall.com/login.html";
}
}
在獲取session的時候不同服務只需要在獲取 redis中session的key即可(session.loginUser.nickname)loginUser為key。
注意:需要使用共享Session的服務都要進行 以上的配置,不然使用不了存在 redis中的Session。
Spring Session原理
Session核心原理:
1)、@EnableRedisHttpSession導入RedisHttpSessionConfiguration配置
1、給容器添加了一個組件RedisIndexedSessionRepository
RedisIndexedSessionRepository:redis操作session。session的增刪改查封裝類
2、SessionRepositoryFilter --》Filter: session存儲的過濾器,每個請求都必須經過filter
1、創建的時候 ,就自動從容器中獲取SessionRepository
2、原始的request,response都被包裝。SessionRequestWrapper,SeesionRepositoryResponseWrapper
3、以后獲取session。request.getSession();
//SessionRepositoryRequestWrapper
4、wrappedRequest.getSession()==>SessionRepositry中獲取的。
裝飾者模式:把原生的請求封裝成自己的
Seesion會自動延期,redis中也是有過期時間的
#### 暑假到現在很久沒更新了 因為在學校沒時間(好吧其實就是因為自己懶哈哈,在學校安逸過頭了)、今天剛弄完谷粒商城分布式Session共享的問題,想要更加詳細的知識關注:https://gitee.com/jinronga/guilimall,不要停止我們的腳步。繼續努力!