1、為什么 依賴了web-session就可以使用redis了?
因為我們引入了 web-session.xml
問: 我們?nèi)绾卧陧椖恐惺褂脀eb-session呢?
答: redis session的使用
2、web-session.xml做了什么
場景介紹:HttpSession 是通過 Servlet 容器創(chuàng)建和管理的,像 Tomcat/Jetty 都是保存在內(nèi)存中的。而如果我們把 web 服務(wù)器搭建成分布式的集群,然后利用 LVS 或 Nginx 做負載均衡,那么來自同一用戶的 Http 請求將有可能被分發(fā)到兩個不同的 web 站點中去。那么問題就來了,如何保證不同的 web 站點能夠共享同一份 session 數(shù)據(jù)呢?
解決方案:使用框架的會話管理工具,也就是spring-session ,可以理解是替換了 Servlet 那一套會話管理,接管創(chuàng)建和管理 Session 數(shù)據(jù)的工作。既不依賴容器,又不需要改動代碼,并且是用了 spring-data-redis 那一套連接池,可以說是最完美的解決方案。
具體實現(xiàn): (已有同學提供實現(xiàn)文檔)
spring-session 的介紹
spring-session 的使用
spring session官方文檔
我們的session數(shù)據(jù)是存放在哪里的呢?我們是存放在redis中的。
redis概要:REmote DIctionary Server(Redis) 是一個高性能的key-value內(nèi)存數(shù)據(jù)庫。之所以說是內(nèi)存數(shù)據(jù)庫,是因為redis基于內(nèi)存的讀取和寫入相比傳統(tǒng)的數(shù)據(jù)庫基于磁盤IO快上數(shù)倍。
jedis概要:那jedis就是集成了redis的一些命令操作,封裝了redis的java客戶端。提供了連接池管理。一般不直接使用jedis,而是在其上在封裝一層,作為業(yè)務(wù)的使用。
由于我們項目是spring框架,可以使用spring 封裝的 redis [Spring Data Redis]。Spring Data Redis提供了四種Redis服務(wù)的Java客戶端包的集成,分別是 Jedis ,JRedis , SRP and Lettuce。
參考文檔:
redis 命令文檔
可視化redis工具下載

3、自定義配置
由于技術(shù)保障部給大家提供了統(tǒng)一使用的包,自然需要提供大家可以自定義配置自己項目的功能。例如設(shè)置session或者cookie的過期時間。這也是這篇文檔相對重點的部分。
在我們自定義配置過程中,我們不是使用繼承的方式來覆蓋配置的。我們實際做的是把它作為一個bean使用。Spring初始化的時候會掃描包, 然后 bean對象由Spring接管, 對象內(nèi)可以注入其他bean對象, 在這里就是注入了 DefaultCookieSerializer 或RedisHttpSessionConfiguration的 bean對象, 而默認的bean對象都是單例的, 所以你這里修改了這個bean對象, 那么系統(tǒng)中這個配置也就改掉了。相當于直接覆蓋。
1 . 配置存在于瀏覽器的cookie

具體分析:有興趣可以看以下org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration的源碼,里面提供的方法都會告訴你提供了哪些配置。摘自-自定義redisoperationssessionrepository官方文檔
maxInactiveIntervalInSeconds - the amount of time before the session will expire in seconds
redisNamespace - allows configuring an application specific namespace for the sessions. Redis keys and channel IDs will start with the prefix of
<redisNamespace>:.redisFlushMode - allows specifying when data will be written to Redis. The default is only when
saveis invoked onSessionRepository. A value ofRedisFlushMode.IMMEDIATEwill write to Redis as soon as possible.
2.配置存在于服務(wù)器的session

具體分析:大家有興趣可進入 org.springframework.session.web.http.DefaultCookieSerializer 看一下,里面分別設(shè)置哪些參數(shù)。以下是可以配置的參數(shù)列表:摘自-自定義cookie配置官方文檔
cookieName- the name of the cookie to use Default "SESSION"
// cookie名稱,默認是SESSIONuseSecureCookie- specify if a secure cookie be used Default use value ofHttpServletRequest.isSecure()at the time of creation.// 在創(chuàng)建時默認使用HttpServletRequest.isSecure()的值cookiePath- the path of the cookie Default is context root
// cookie路徑,默認是內(nèi)容跟目錄的路徑cookieMaxAge- specifies the max age of the cookie to be set at the time the session is created. Default is -1 which indicates the cookie will be removed when the browser is closed.
// 指定在創(chuàng)建會話時要設(shè)置的Cookie的最大年齡。默認值是-1,這意味著當瀏覽器關(guān)閉時cookie將被刪除。jvmRoute- specifies a suffix to be appended to the session id and included in the cookie. Used to identify which JVM to route to for session affinity. With some implementations (i.e. Redis) this provides no performance benefit. However, this can help with tracing logs of a particular user.domainName- allows specifying a specific domain name to be used for the cookie. This option is simple to understand, but will likely require a different configuration between development and production environments. See domainNamePattern as an alternative.
// 允許指定用于Cookie的特定域名。建議使用domainNamePattern作為備選方案,因為正式和測試的選項不一樣。domainNamePattern- a case insensitive pattern used to extract the domain name from theHttpServletRequest#getServerName(). The pattern should provide a single grouping used to extract the value of the cookie domain. If the regular expression does not match, no domain is set and the existing domain will be used. If the regular expression matches, the first grouping will be used as the domain.
// 正則匹配域名
4、配置后的現(xiàn)象
實驗方案:建立2個頁面,分別名為:about.page, help.page
我在 about.page 寫如下代碼
// 往redis設(shè)值的過程
String unionId = "bbbb";
WebUser user = userDelegator.weixinGetSession(unionId);
String uid = user.getUid();
String sessionId = user.getSessionId();
session.setAttribute("uid", uid);
session.setAttribute("sessionId", sessionId);
String sessionGetId = session.getId();
System.out.println("sessionGetId " + sessionGetId);
System.out.println("uid:" + session.getAttribute("uid"));
System.out.println("sessionId:" + session.getAttribute("sessionId"));
我在 help.page 寫如下代碼
// 從redis取值
System.out.println("uid" + session.getAttribute("uid"));
System.out.println("sessionId" + session.getAttribute("sessionId"));
運行頁面 結(jié)果:

測試結(jié)論:
- 當我打開about頁面以后,我瀏覽器cookie中的JSSESSION就是我插入redis 的key,我根據(jù)cookie中JSESSIONID的值去redis里面查找,可以redis可視化街面上看見,我插入的參數(shù)。都是與我配置的相一致。
- 當我600s以內(nèi)打開about頁面或help頁面,我的JSESSIONID沒有變化,但當我600s以后再打開頁面about頁面或help頁面,cookie中的JSESSIONID發(fā)生了改變。也就是說600s后,我之前的會話ID已經(jīng)失效。頁面對你這個人訪問的記錄已經(jīng)重置。
- 600s+300s后(600s 是我在cookie里面設(shè)置的過期時間,而session中key的過期時間是在cookie過期時間的基礎(chǔ)上+300s = 900s)可視化里的那條記錄將提示您過期。提示文案如下:
Cannot open value tab: Cannot load key spring:session:campaign:expirations:1538208900000 because it doesn't exist in database. Please reload connection tree and try again.