springSession
是spring
旗下的一個項目,把servlet
容器實現的httpSession
替換爲springSession
,專一於解決session
管理問題。可簡單快速且無縫的集成到咱們的應用中。本文經過一個案例,使用SpringBoot
來集成SpringSession
,而且使用Redis
做爲存儲來實踐下SpringSession
的使用。java
由於須要使用Redis
做爲底層Session
的存儲介質,實現分佈式session
,所以須要安裝Redis
。web
一、從官網下載最新版的Redis
redis
二、解壓spring
tar zxvf redis-5.0.0.tar.gz
複製代碼
三、編譯測試瀏覽器
sudo make test
複製代碼
四、編譯安裝緩存
sudo make install
複製代碼
五、安裝問題bash
若是您以前安裝過,重複安裝且沒有卸載乾淨的話,會報下面的錯服務器
make[1]: *** [test] Error 1
make: *** [test] Error 2
複製代碼
解決這個錯誤,執行下面的語句便可:cookie
make distclean
make
make test
複製代碼
正確安裝姿式以下:session
六、啓動Redis
在您的Redis
安裝目錄下,有 redis-server
,執行該腳本命令:
OK,到這裏,Redis
的安裝工做完畢。
這裏咱們直接經過Idea
來構建咱們的SpringBoot
工程。
File->New->Project : Spring Initializr
複製代碼
OK,SpringBoot
工程準備完畢,這裏選擇建立的是一個Web
工程。
集成主要是依賴引入,這裏須要redis
和session
的依賴
<dependencies>
<!--redis 依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--sessions 依賴-->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
</dependencies>
複製代碼
#服務端口
server.port=8080
#redi主機地址
spring.redis.host=localhost
#redis服務端口
spring.redis.port=6379
# spring session使用存儲類型,spirngboot默認就是使用redis方式,若是不想用能夠填none。
spring.session.store-type=redis
複製代碼
@SpringBootApplication
@EnableRedisHttpSession
public class SpringBootSessionApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootSessionApplication.class, args);
}
}
複製代碼
先來編寫一個Controller
/** * SessionController * * @author: glmapper@leishu * @since: 18/11/3 下午3:16 * @version 1.0 **/
@Controller
@RequestMapping(value = "/")
public class SessionController {
@ResponseBody
@RequestMapping(value = "/session")
public Map<String, Object> getSession(HttpServletRequest request) {
request.getSession().setAttribute("userName", "glmapper");
Map<String, Object> map = new HashMap<>();
map.put("sessionId", request.getSession().getId());
return map;
}
@ResponseBody
@RequestMapping(value = "/get")
public String get(HttpServletRequest request) {
String userName = (String) request.getSession().getAttribute("userName");
return userName;
}
}
複製代碼
啓動SpringBoot
工程;而後瀏覽器中輸入地址 http://localhost:8080/session;
Controller
中的第一個方法
getSession
,這個方法向
session
中設置了一個值。
下面咱們執行:http://localhost:8080/get 這裏是從session
中取值:
到此,SpringBoot
整合 SpringSession
的過程就完成了。這裏咱們只是引入了依賴,而後作了簡單的配置,那麼咱們的請求是如何被 SpringSession
處理的呢?從咱們一向的認知來看,對於基於Servlet
規範的容器(SpringBoot
使用的是嵌入式Tomcat
)的應用,請求最早被處理的是Filter
。咱們在基於Spring+SpringMvc
這套技術棧開發時,若是咱們須要作權限管理,經過會基於Filter
或者攔截器。可是這裏貌似咱們什麼也沒作,可是請求確實被SpringSession
處理了。OK,咱們來扒一扒。
SpringBoot
的啓動日誌;上圖紅色框內的是當前應用註冊是
Filter
信息,從這裏能夠看到有個和
session
有關的
Filter:sessionRepositoryFilter
;這個
bean
對應的類是:
org.springframework.boot.autoconfigure.session.SessionRepositoryFilterConfiguration.ConditionalOnBean=
org.springframework.session.web.http.SessionRepositoryFilter
複製代碼
在這裏找到了
這裏涉及到SpringBoot
的自動配置,從spring-boot-autoconfig
包下加載spring-autoconfigure-metadata.properties
配置文件,而後獲取全部支持自動配置的信息;SpringSession
也在其中。關於如何加載而且註冊不在本文的範疇以內,咱們繼續來分析SpringSession
的處理過程。
從上面SpringBoot
的啓動過程咱們找到了處理session
的Filter
,而後知道了它是經過自動配置的方式被註冊到當前的容器而且來處理請求。
@Order(SessionRepositoryFilter.DEFAULT_ORDER)
public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFilter {
複製代碼
從SessionRepositoryFilter
的定義來看:
Order
,而且配置了一個很小的值(Integer.MIN_VALUE + 50
),以此來確保session
的Filter
在Filter
鏈中被優先執行。OncePerRequestFilter
,確保在一次請求只經過一次filter
,而不須要重複執行爲何 session
的 Filter
要被優先執行呢?由於咱們的請求被包裝了,若是SessionRepositoryFilter
不優先處理請求,可能會致使後續的請求行爲不一致,這裏涉及到 springSession
無縫替換應用服務器的request
的原理:
Filter
,實現doFilter
方法HttpServletRequestWrapper
、HttpServletResponseWrapper
類,重寫getSession
等相關方法(在這些方法裏調用相關的 session
存儲容器操做類)。request
和response
類;並把它們分別傳遞到過濾器鏈filter
配置到過濾器鏈的第一個位置上OK,瞭解了這些背景,咱們來跟蹤下整個處理流程。
從這裏能夠看到request
和response
類被包裝了。
這裏是從Redis
中拿咱們session
數據的地方
先從咱們當前servlet
容器中去拿,若是拿到則直接返回
去Redis
中取
Reids
中去查一次,避免一次與Reids
的交互。
session
sessionId
,而且根據當前sessionId
去Reids
中查找session
數據session,sessionId,requestedSessionCached
等數據狀態若是Redis
中有,則更新session
相關信息並返回
若是Reids
中沒有找到,則根據 create
來判斷是否建立新的session
。
SpringSession
提供了兩種保存和傳遞SessionId
的方式,一種是基於Cookie
的,一種是基於Header
的。SpringSession
中默認使用的是基於Cookie
的方式。readCookieValues
就是實現如何從Cookie
中獲取sessionId
的。
這個過程其實很簡單,先是從request
中獲取當前請求攜帶的因此的Cookie
信息,而後將匹配到的 cookieName
爲 「SESSION」
的Cookie
進行解析。
這裏是從Redis
中取session
數據的地方
sessionId
從 Redis
中取到 entries
數據RedisSession
並返回commitSession
做用是經過HttpSessionIdResolver
將sessionId
寫到response
,而且進行持久化。
這裏的 session
實際上是已經更新過狀態的,好比從新設置了 session
的過時時間等。session
提交實際上就意味着當前請求已經處理完畢了。
本文先介紹瞭如何使用 SpringBoot
集成 SpringSession
,而且以 Redis
做爲存儲。而後簡單分析了 SpringSession
的處理過程,本文對 SpringSession
的原理部分沒有進行深刻分析,下一篇分析下SpringSession
的原理。