簡介
解決web服務集群session共享問題,原理不做介紹!
基本原理
- 過濾器(SessionRepositoryFilter),過濾請求。
- 繼承servlet接口,對request、response進行封裝擴展,重寫session相關方法。
使用
pom依賴
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>1.3.0.RELEASE</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
jar版本適配問題個人解決。
spring-session.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
<!--session 有效期,時間單位:秒-->
<property name="maxInactiveIntervalInSeconds" value="1800"/>
<!--spring session key 命名前綴,用於項目區分-->
<property name="redisNamespace" value="project"/>
</bean>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!--資源池中最大連接數-->
<property name="maxTotal" value="20" />
<!--資源池允許最大空閑的連接數-->
<property name="maxIdle" value="20" />
<!--資源池確保最少空閑的連接數-->
<property name="minIdle" value="5"/>
<!--當資源池用盡后,調用者是否要等待。只有當為true時,下面的maxWaitMillis才會生效-->
<property name="blockWhenExhausted" value="true"/>
<!--當資源池連接用盡后,調用者的最大等待時間(單位為毫秒)-->
<property name="maxWaitMillis" value="1000"/>
<!--向資源池借用連接時是否做連接有效性檢測(ping),無效連接會被移除-->
<property name="testOnBorrow" value="false"/>
<!--向資源池歸還連接時是否做連接有效性檢測(ping),無效連接會被移除-->
<property name="testOnReturn" value="false"/>
<!--是否開啟空閑資源監測-->
<property name="testWhileIdle" value="true"/>
<!--空閑資源的檢測周期(單位為毫秒)-->
<property name="timeBetweenEvictionRunsMillis" value="30000"/>
<!--資源池中資源最小空閑時間(單位為毫秒),達到此值后空閑資源將被移除-->
<property name="minEvictableIdleTimeMillis" value="60000"/>
<!--做空閑資源檢測時,每次的采樣數, -1:所有-->
<property name="numTestsPerEvictionRun" value="-1"/>
</bean>
<!--redis connection配置-->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
<property name="hostName" value="#{config['redis.host']}"/>
<property name="port" value="#{config['redis.port']}"/>
<property name="database" value="#{config['redis.db.session']}"/>
<property name="timeout" value="3000"/>
<property name="usePool" value="true"/>
<property name="poolConfig" ref="jedisPoolConfig"/>
</bean>
<!-- 讓Spring Session不再執行config命令 -->
<util:constant static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>
</beans>
web.xml配置
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
過濾器的順序問題:
- CharacterEncodingFilter,設置請求編碼。否則可能產生中文亂碼問題。
- springSessionRepositoryFilter,spring session 過濾器,攔截所有請求。
- requestContextFilter,如項目中存在直接注入 request的情況,需設置,否則 request 中獲取到的session不可用。
FindByIndexNameSessionRepository
使用 springsecurtiy 的項目,spring session 會保存用戶名下所有的會話ID。該key在用戶主動退出時會刪除,但自動過期的情況下沒有做清理,會導致冗余垃圾數據的產生。
解決方法:
redis-cli config set notify-keyspace-events Egx
開啟redis的keyspace事件。
或者定時掃描清理
注意事項
- session中存儲的對象需要可序列化。
- 過濾器順序問題
- spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:* 的問題
