一般狀況下,Tomcat、Jetty等Servlet容器,會默認將Session保存在內存中。若是是單個服務器實例的應用,將Session保存在服務器內存中是一個很是好的方案。可是這種方案有一個缺點,就是不利於擴展。html
目前愈來愈多的應用採用分佈式部署,用於實現高可用性和負載均衡等。那麼問題來了,若是將同一個應用部署在多個服務器上經過負載均衡對外提供訪問,如何實現Session共享?html5
實際上實現Session共享的方案不少,其中一種經常使用的就是使用Tomcat、Jetty等服務器提供的Session共享功能,將Session的內容統一存儲在一個數據庫(如MySQL)或緩存(如Redis)中。我在之前的一篇博客中有介紹如何配置Jetty的Session存儲在MySQL或MongoDB中。java
本文主要介紹另外一種實現Session共享的方案,不依賴於Servlet容器,而是Web應用代碼層面的實現,直接在已有項目基礎上加入Spring Session框架來實現Session統一存儲在Redis中。若是你的Web應用是基於Spring框架開發的,只須要對現有項目進行少許配置,便可將一個單機版的Web應用改成一個分佈式應用,因爲不基於Servlet容器,因此能夠隨意將項目移植到其餘容器。web
Maven依賴
在項目中加入Spring Session的相關依賴包,包括Spring Data Redis、Jedis、Apache Commons Pool:redis
1 |
<!-- Jedis --> |
配置Filter
在web.xml中加入如下過濾器,注意若是web.xml中有其餘過濾器,通常狀況下Spring Session的過濾器要放在第一位。spring
1 |
<filter> |
Spring配置文件
1 |
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/> |
只須要以上簡單的配置,至此爲止即已經完成Web應用Session統一存儲在Redis中,能夠說是及其簡單。數據庫
解決Redis雲服務Unable to configure Redis to keyspace notifications異常
若是是自建服務器搭建Redis服務,以上已經完成了Spring Session配置,這一節就不用看了。不過不少公司爲了穩定性、減小運維成本,會選擇使用Redis雲服務,例如阿里雲數據庫Redis版、騰訊雲存儲Redis等。使用過程當中會出現異常:apache
1 |
Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'enableRedisKeyspaceNotificationsInitializer' defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: |
實際上這種異常發生的緣由是,不少Redis雲服務提供商考慮到安全因素,會禁用掉Redis的config命令:禁用config命令
在錯誤提示連接的文檔中,能夠看到Redis須要如下的配置:
api
1 |
redis-cli config set notify-keyspace-events Egx |
首先要想辦法給雲服務Redis加上這個配置。
部分Redis雲服務提供商能夠在對應的管理後臺配置:配置notify-keyspace-events
若是不能在後臺配置,能夠經過工單聯繫售後工程師幫忙配置,例如阿里雲:阿里雲工單
完成以後,還須要在Spring配置文件中加上一個配置,讓Spring Session再也不執行config命令:
However, in a secured Redis enviornment the config command is disabled. This means that Spring Session cannot configure Redis Keyspace events for you. To disable the automatic configuration add ConfigureRedisAction.NO_OP as a bean.
配置:
1 |
<?xml version="1.0" encoding="UTF-8"?> |