使用SpringSession管理分布式系統的會話Session


在我方供應鏈項目分布式部署的環境下,需要在統一網關服務中管理訪問的Session,即無論訪問請求路由到哪一個網關服務環境,使用的都是相同的HttpSession,這樣就保證了在用戶登錄之后,能夠使用統一的Session來處理鑒權和其他邏輯,這對於分布式系統的用戶會話管理是必要的。為了能夠達到這個目的,我們引入了SpringSession。

SpringSession是什么

SpringSession是Spring框架大集合下的一個子組件,使用Redis來備份Web服務訪問生成的(被加工過的)HttpSession,當你在使用SpringBoot框架的時候,你能夠很方便的集成和使用它。

SpringSession如何使用

1、增加依賴

當你在使用SpringBoot框架並采用maven來管理依賴庫時,你只需增加下面的依賴:

1 <dependencies>
2     <!-- ... -->
3 
4     <dependency>
5         <groupId>org.springframework.session</groupId>
6         <artifactId>spring-session-data-redis</artifactId>
7     </dependency>
8 </dependencies>

幸運的是,當你在使用SpringBoot框架時,你不需要手動指定依賴的具體版本,它會幫你自動管理。

2、SpringBoot配置項

得益於SpringBoot的自動配置管理支持,在設置使用Redis備份SpringSession時,我們只需要在application.properties增加如下內容:

# Session store type.
spring.session.store-type=redis 

在如上的配置驅動下,我們再在SpringBoot的配置管理下增加@EnableRedisHttpSession注解,它會自動創建一個名稱為SpringSessionReposityFilter且實現了Filter接口的(過濾器)類,這個過濾器將負責替換HttpSession的實現為SpringSession。

更多關於SpringSession的配置如下:

# Session timeout. If a duration suffix is not specified, seconds is used.
server.servlet.session.timeout= 

# Sessions flush mode.
spring.session.redis.flush-mode=on-save 

# Namespace for keys used to store sessions.
spring.session.redis.namespace=spring:session 

3、配置Redis連接

其實SpringBoot會自動創建一個叫做RedisConnectionFactory的類來管理SpringSession與Redis服務的連接,默認是連接到localhost端口為6379的Redis服務,但是在生產環境中,那就必須將這種與Redis服務器連接的配置進行自定義更改,你可以按照如下代碼清單所例舉的方式將配置追加到application.properties文件中:

# Redis server host.
spring.redis.host=localhost 

# Login password of the redis server.
spring.redis.password= 

# Redis server port.
spring.redis.port=6379 

當然,如果你的SpringBoot中自有管理與Redis服務器的連接,你同樣可以在你的Configuration將這個連接復用給這里的配置,比如你使用JedisShardInfo。

以下是使用JedisShardInfo的代碼參考:

 1 @Bean("jedisShardInfo")
 2 public JedisShardInfo jedisShardInfo(@Value("${jedis.redis.uri}") String uri,
 3                                      @Value("${catalog.redis.tesla}") String redisCatalog) {
 4     String redisUri = uri;
 5     redisUri = getRedisUri(redisCatalog, redisUri);
 6     return new JedisShardInfo(redisUri);
 7 }
 8 
 9 private String getRedisUri(String redisCatalog, String redisUri) {
10     if(!StringUtils.isEmpty(redisCatalog)) {
11         log.info("===> Redis use unified configuration.");
12         DataSourceInstanceConfig dbInstanceConfig = DBLoader.getDataSourceInstanceConfig(redisCatalog);
13         RedisServerInfo serverInfo = dbInstanceConfig.getServer(RedisServerInfo.class).get(0);
14         redisUri = REDIS_URI_PREFIX.concat(serverInfo.getPassword()).concat("@")
15                 .concat(serverInfo.getHost()).concat(":")
16                 .concat(serverInfo.getPort()).concat("/")
17                 .concat(serverInfo.getDb());
18         log.info("===> redis_uri: {}", redisUri);
19     }
20     return redisUri;
21 }
22 
23 @Configuration
24 @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 172800)
25 public class HttpSessionConfig {
26     @Bean
27     public static ConfigureRedisAction configureRedisAction() {
28         return ConfigureRedisAction.NO_OP;
29     }
30 
31     @Bean
32     public JedisConnectionFactory connectionFactory(@Autowired @Qualifier("jedisShardInfo") JedisShardInfo jedisShardInfo){
33         return new JedisConnectionFactory(jedisShardInfo);
34     }
35 }
View Code

4、Servlet容器初始化

在SpringBootConfiguration的配置驅動下,自動創建的SpringSessionRepositoryFilter將負責替換系統的HttpSession為SpringSession並保存於redis中,為了這個攔截器能夠發揮作用,Spring需要將這個過濾器納入配置管理,最后我們還需要確保Servlet容器能夠正確的使用這個攔截器攔截到所有請求,幸運的是,SpringBoot為我們顧及到了所有的這些步驟。

SpringSession的實現原理是什么

和我們使用Tomcat的HttpSession不同的是,我們將這個會話內容持久化到了Redis中。SpringSession將HttpSession替換為一種新的實現,並將它保存到了Redis中,也就是當我們的SpringSecurity的SecurityContextPersistenceFilter在保存了SecurityContext到HttpSession之后,就會觸發這個替換機制保存到Redis中。

當我們發起訪問請求的時候,系統會創建一個HttpSession,而SpringSesion會創建一個名稱為SESSION的cookie放到你瀏覽器的中,這個cookie的內容包含了你session的ID,你可以在你的Chrome瀏覽器控制台中查看到。

於此同時,你也可以在你的redis服務器中看到,找到以application.properties中配置的命名空間開頭的key值,然后你會看到包含和瀏覽器上看到的SESSION相同內容的key,當然你可以在redis服務器中使用redis-cli命令去查看或者刪除它。

當你瀏覽器每次發起Http請求到服務端時,都會攜帶這個cookie內容,服務端SpringSession接受到這個cookie值之后就自動去redis中找到相同的會話Session,由此來識別出是同一個用戶進行的訪問。

參考資料

1、https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot-redis.html

2、http://blog.didispace.com/spring-session-xjf-2/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM