SpringBoot Session Redis 實現與簡析
一、Spring Session Redis
1、配置spring session redis相關maven依賴
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
<!-- spring session -->
<dependency>
< groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
2、專案配置spring session儲存型別為redis,並對redis配置
spring.session.store-type=redis spring.redis.host=47.97.23.184 spring.redis.port=6379 spring.redis.jedis.pool.max-active=8 spring.redis.jedis.pool.max-wait=30 spring.redis.jedis.pool.max-idle=8 spring.redis.jedis.pool.min-idle=0 spring.redis.jedis.timeout=10
3、啟用 @EnableRedisHttpSession
(不配置RedisHttpSessionConfig,直接在啟動類中新增此註解即可)
1)第一種,直接在啟動類中啟用 @EnableRedisHttpSession
@SpringBootApplication
@EnableRedisHttpSession
public class SpringSessionApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSessionApplication.class , args);
}
}
2)第二種,不修改啟動類,增加一個RedisHttpSessionConfig配置類
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
@Configuration
@EnableRedisHttpSession
public class RedisHttpSessionConfig {
/**
* @EnableRedisHttpSession的SessionMessageListener和啟用必要的Redis KEYSPACE事件是自動完成的。
* 但是,在安全的Redis環境中,config命令被禁用。這意味著Spring Session無法為您配置Redis Keyspace事件。
* 要禁用自動配置,請新增ConfigureRedisAction.NO_OP為bean
* @return
*/
@Bean
public static ConfigureRedisAction configureRedisAction() {
return ConfigureRedisAction.NO_OP;
}
}
二、專案訪問
訪問地址
http://localhost:8080/session/test
測試結果
127.0.0.1:6379> keys *
1) "spring:session:sessions:expires:01cc33eb-aceb-4109-98ad-651a0a9bd40d"
2) "spring:session:sessions:01cc33eb-aceb-4109-98ad-651a0a9bd40d"
3) "spring:session:expirations:1539163980000"
127.0.0.1:6379> object encoding spring:session:sessions:01cc33eb-aceb-4109-98ad-651a0a9bd40d
"hashtable"
表示session儲存的是hash資料結構,故而直接存放各種key/value即可
三、原始碼簡析
1、從入口標籤@EnableRedisHttpSession 進入檢視原始碼,發現其import 匯入了類 RedisHttpSessionConfiguration,接著點進去,重點在其父類 SpringHttpSessionConfiguration
public class SpringHttpSessionConfiguration implements ApplicationContextAware
2、在SpringHttpSessionConfiguration中SessionRepositoryFilter(會話過濾器)是Spring Session最核心的地方。其中最重要的方法doFilterInternal如下:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);
SessionRepositoryFilter<S>.SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryFilter.SessionRepositoryRequestWrapper(request, response, this.servletContext);
SessionRepositoryFilter.SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryFilter.SessionRepositoryResponseWrapper(wrappedRequest, response);
try {
//將filter新增到FilterChain中
filterChain.doFilter(wrappedRequest, wrappedResponse);
} finally {
//儲存session資訊
wrappedRequest.commitSession();
}
}
SessionRepositoryFilter 實現了doFilterInternal,方法內部建立了SessionRepositoryRequestWrapper、SessionRepositoryResponseWrapper,將filter新增到FilterChain中,最後呼叫commitSession()儲存session資訊到redis
FilterChain:過濾器鏈作用,當一個filter收到請求的時候,呼叫chain.doFilter才可以訪問下一個匹配的filter,若當前的filter是最後一 個filter,呼叫chain.doFilter才能訪問目標資源。多個filter的執行順序是由web.xml中filter-mapping的位置決定的.
Spring Session Redis 原始碼分析可參考 https://blog.csdn.net/u010648555/article/details/79491988,分析得很詳細。
四、異常彙總
1、未發現RedisConnectionFactory 類
No qualifying bean of type 'org.springframework.data.redis.connection.RedisConnectionFactory' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Description:
Parameter 1 of method sessionRepositoryFilterRegistration in org.springframework.boot.autoconfigure.session.SessionRepositoryFilterConfiguration required a bean of type ‘org.springframework.data.redis.connection.RedisConnectionFactory’ that could not be found.
- Bean method ‘redisConnectionFactory’ not loaded because @ConditionalOnClass did not find required classes ‘org.apache.commons.pool2.impl.GenericObjectPool’, ‘redis.clients.jedis.Jedis’
- Bean method ‘redisConnectionFactory’ not loaded because @ConditionalOnClass did not find required class ‘io.lettuce.core.RedisClient’
Action:
Consider revisiting the entries above or defining a bean of type ‘org.springframework.data.redis.connection.RedisConnectionFactory’ in your configuration.
解決方法:引入jedis maven依賴
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
2、因安全的Redis環境,無法操作Config自動配置報錯
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]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Unable to configure Redis to keyspace notifications. See http://docs.spring.io/spring-session/docs/current/reference/html5/#api-redisoperationssessionrepository-sessiondestroyedevent
解決方法
@EnableRedisHttpSession的SessionMessageListener和啟用必要的Redis KEYSPACE事件是自動完成的。但是,在安全的Redis環境中,config命令被禁用。這意味著Spring Session無法為您配置Redis Keyspace事件。要禁用自動配置,請新增ConfigureRedisAction.NO_OP為bean。
在RedisHttpSessionConfig中新增程式碼:
@Bean
public static ConfigureRedisAction configureRedisAction() {
return ConfigureRedisAction.NO_OP;
}
3、Redis無法連線
Redis需要設定可遠端訪問
redis.conf中註釋掉bind、並將 protected-mode yes 設定為 protected-mode no