springboot集成springsession如何實(shí)現(xiàn)分布式session共享
前言
現(xiàn)在隨著分布式,微服務(wù)架構(gòu)的日益成熟,越來(lái)越多的企業(yè)將傳統(tǒng)的單體服務(wù)改造成微服務(wù)或者分布式架構(gòu)。
當(dāng)然不是說(shuō)單體服務(wù)現(xiàn)在是百無(wú)一用,只能說(shuō)沒(méi)有最好的,只要適合就好。
在分布式服務(wù)改造中,大家都遇到過(guò)一個(gè)問(wèn)題,那就是分布式session管理。
之前的單體服務(wù)session是保存在容器的內(nèi)存中的。
微服務(wù)架構(gòu)中一個(gè)服務(wù)為了實(shí)現(xiàn)高可用都是至少3個(gè)點(diǎn)部署,這樣就遇到一個(gè)問(wèn)題,就是這個(gè)部署在不同服務(wù)器上的三個(gè)點(diǎn)如何實(shí)現(xiàn)共享session呢?
其實(shí)解決方案是很多的,原理也是差不多的。比如說(shuō)我們現(xiàn)在項(xiàng)目就是將session保存在數(shù)據(jù)庫(kù)中,這樣三個(gè)點(diǎn)都去讀取數(shù)據(jù)庫(kù)來(lái)實(shí)現(xiàn)session共享。
還有的方案就是大家比較熟悉的將session存儲(chǔ)在redis中,而且redis支持key設(shè)置過(guò)期時(shí)間,這個(gè)和用戶會(huì)話的過(guò)期就不謀而合了。
只不過(guò)傳統(tǒng)的集成方案需要我們手動(dòng)的將session存儲(chǔ)在redis中,然后再在redis中讀取,這種方式操作起來(lái)可能比較重復(fù)繁瑣。
所以spring已經(jīng)在spring全家桶中提供了分布式session共享集成方案,就是標(biāo)題中所說(shuō)的springsession。
這里基于springboot來(lái)搭建個(gè)入門demo,以便大家快速了解springsession。
集成springsession之前
這里簡(jiǎn)單搭建了兩個(gè)服務(wù)client1和cilent2,我們?cè)谶@連個(gè)服務(wù)中提供兩個(gè)接口,如下
/** * @author 蔣墨風(fēng) * @title: SpringSessionController * @projectName client1 * @description: 測(cè)試spring session功能 * @date 2019/10/27 16:11 */ @RequestMapping("/springSessionTest") @RestController public class SpringSessionController { @RequestMapping(value = "/test", method = RequestMethod.GET) public Map<String, Object> firstResp (HttpServletRequest request){ Map<String, Object> map = new HashMap<>(); request.getSession().setAttribute("request Url", request.getRequestURL()); map.put("request Url", request.getRequestURL()); return map; } @RequestMapping(value = "/sessions", method = RequestMethod.GET) public Object sessions (HttpServletRequest request){ Map<String, Object> map = new HashMap<>(); map.put("sessionId", request.getSession().getId()); map.put("message", request.getSession().getAttribute("request Url")); return map; } }
client2中的接口和client1代碼是一樣的,這里就不重復(fù)粘貼了。
兩個(gè)服務(wù)的端口分別是9002和9003。這里我們把兩個(gè)服務(wù)啟動(dòng)成功之后,我們先訪問(wèn)client1的test接口,然后在訪問(wèn)client1中sessions接口來(lái)看下具體session打印。
client1中的sessions接口響應(yīng)如下
{ "sessionId":"6C3E8502E1DFA9FB5595D8EEE848A900", "message":"http://localhost:9002/springSessionTest/test" }
接下來(lái)我們依次訪問(wèn)client2接口中的test接口和sessions接口,得到的響應(yīng)如下
{ "sessionId":"B6DEB7D49CCA3AA239FA593555605C4B", "message":"http://localhost:9003/springSessionTest/test" }
可以看到兩個(gè)session是相互獨(dú)立的。
集成springsession之后
首先我們?cè)趦蓚€(gè)服務(wù)中引入相關(guān)的依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
然后在配置文件中加上redis配置
spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.database=3 spring.redis.password=12345 spring.redis.timeout=5000
再在兩個(gè)服務(wù)的啟動(dòng)類上加上@EnableRedisHttpSession注解,開(kāi)啟spring session功能,兩個(gè)服務(wù)正常啟動(dòng)之后,重復(fù)上面操作,先訪問(wèn)client1的test和sessions接口,接口響應(yīng)如下
{ "sessionId":"5fdd9b56-70ab-4722-81f6-8c4af721a1e6", "message":"http://localhost:9002/springSessionTest/test" }
接下來(lái)我們?cè)僭L問(wèn)client2服務(wù)中的test,sessions接口,接口響應(yīng)如下
{ "sessionId":"5fdd9b56-70ab-4722-81f6-8c4af721a1e6", "message":"http://localhost:9003/springSessionTest/test" }
可以看到兩個(gè)sessionId是一樣的,所以client1和client2的共享session是實(shí)現(xiàn)了的,網(wǎng)上好多小伙伴說(shuō),你這種實(shí)現(xiàn)方式是兩個(gè)服務(wù)部署在同一臺(tái)機(jī)器上,如果把兩個(gè)服務(wù)分別部署在兩臺(tái)機(jī)器上,上面的測(cè)試效果就不是這樣了,如果遇到這種情況的小伙伴可能需要確認(rèn)下自己測(cè)試的兩臺(tái)機(jī)器上的時(shí)間是不是一致,如果不是的話,就可能會(huì)導(dǎo)致上面的測(cè)試失敗。
總結(jié)
上面只是簡(jiǎn)單的演示了下兩個(gè)服務(wù)集成springsession之前和之后的效果,具體springsession的原理,后面結(jié)合springsession源碼來(lái)和大家一起學(xué)習(xí),這里springsession集成了redis,用redis做session存儲(chǔ),當(dāng)然我們也可以使用其他的存儲(chǔ),不局限于redis。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBean和Controller實(shí)現(xiàn)動(dòng)態(tài)注冊(cè)與注銷過(guò)程詳細(xì)講解
這篇文章主要介紹了SpringBean和Controller實(shí)現(xiàn)動(dòng)態(tài)注冊(cè)與注銷過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-02-02Spring事務(wù)注解@Transactional失效的八種場(chǎng)景分析
最近在開(kāi)發(fā)采用Spring框架的項(xiàng)目中,使用了@Transactional注解,但發(fā)現(xiàn)事務(wù)注解失效了,所以這篇文章主要給大家介紹了關(guān)于Spring事務(wù)注解@Transactional失效的八種場(chǎng)景,需要的朋友可以參考下2021-05-05mybatis@insert?注解如何判斷insert或是update
這篇文章主要介紹了mybatis@insert?注解如何判斷insert或是update,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07關(guān)于Java中try finally return語(yǔ)句的執(zhí)行順序淺析
這篇文章主要介紹了關(guān)于Java中try finally return語(yǔ)句的執(zhí)行順序淺析,需要的朋友可以參考下2017-08-08Java 中的vector和list的區(qū)別和使用實(shí)例詳解
在大家還沒(méi)有了解vector,list,deque的知識(shí)之前,我先給大家介紹下stl,本文重點(diǎn)給大家介紹vector和list的區(qū)別及使用,感興趣的的朋友一起看看吧2017-09-09Spring實(shí)戰(zhàn)之抽象Bean和子Bean定義與用法示例
這篇文章主要介紹了Spring實(shí)戰(zhàn)之抽象Bean和子Bean定義與用法,結(jié)合實(shí)例形式分析了Spring抽象Bean和子Bean相關(guān)配置、定義與使用操作技巧,需要的朋友可以參考下2019-11-11java中StringBuffer的length()和capacity()方法對(duì)比
這篇文章主要介紹了java中StringBuffer的length()和capacity()方法對(duì)比,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07java使用ffmpeg實(shí)現(xiàn)上傳視頻的轉(zhuǎn)碼提取視頻的截圖等功能(代碼操作)
這篇文章主要介紹了java使用ffmpeg實(shí)現(xiàn)上傳視頻的轉(zhuǎn)碼,提取視頻的截圖等功能,本文圖文并茂給大家介紹的非常詳細(xì),對(duì)大家的工作或?qū)W習(xí)具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03Java后端Cookie實(shí)現(xiàn)(時(shí)間戳)代碼實(shí)例
這篇文章主要介紹了Java后端Cookie實(shí)現(xiàn)(時(shí)間戳)代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12Java中的java.lang.reflect.Type簡(jiǎn)介
在 Java 中,java.lang.reflect.Type 是一個(gè)接口,代表所有類型的通用超類型,它包括原始類型、參數(shù)化類型、數(shù)組類型、類型變量和基本類型,本文給大家講解Java中的java.lang.reflect.Type是什么,需要的朋友可以參考下2024-06-06