1. 程式人生 > 實用技巧 >SpringSesion共享使用、自定義Session作用域

SpringSesion共享使用、自定義Session作用域

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是父域名不能拿到子域名的資訊。

程式碼

spring session guide

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,不要停止我們的腳步。繼續努力!