1. 程式人生 > >SpringBoot Session Redis 實現與簡析

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