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

猜你喜欢

转载自blog.csdn.net/yyhcsfy/article/details/83145954