将 spring-session 从 1.0.0.RC1 升级到 1.0.0.RELEASE 时出现 JedisDataException

JedisDataException when upgrading spring-session from 1.0.0.RC1 to 1.0.0.RELEASE

我们正在尝试从 RC1 升级到 RELEASE,但现在出现以下异常:

Caused by: redis.clients.jedis.exceptions.JedisDataException: ERR unknown command 'CONFIG'
        at redis.clients.jedis.Protocol.processError(Protocol.java:100) ~[Protocol.class:na]
        at redis.clients.jedis.Protocol.process(Protocol.java:118) ~[Protocol.class:na]
        at redis.clients.jedis.Protocol.read(Protocol.java:187) ~[Protocol.class:na]
        at redis.clients.jedis.Connection.getBinaryMultiBulkReply(Connection.java:212) ~[Connection.class:na]
        at redis.clients.jedis.Connection.getMultiBulkReply(Connection.java:205) ~[Connection.class:na]
        at redis.clients.jedis.Jedis.configGet(Jedis.java:2701) ~[Jedis.class:na]
        at org.springframework.data.redis.connection.jedis.JedisConnection.getConfig(JedisConnection.java:531) ~[JedisConnection.class:1.3.0.RELEASE]
        ... 29 common frames omitted

这是我的会话配置:

@EnableRedisHttpSession
public class SessionConfig {

    private static final int SESSION_EXPIRATION_TIME = 28800; 

    @Autowired
    private Environment env;

    @Bean
    public JedisConnectionFactory connectionFactory() {
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
        jedisConnectionFactory.setHostName(env.getProperty("reddis.host"));
        jedisConnectionFactory.setPort(env.getProperty("reddis.port", Integer.class));
        return jedisConnectionFactory;
    }

    @Bean
    public HttpSessionStrategy httpSessionStrategy() {
        return new HeaderHttpSessionStrategy();
    }

    @Bean
    public RedisOperationsSessionRepository sessionRepository() {
        RedisOperationsSessionRepository redisOperationsSessionRepository = new RedisOperationsSessionRepository(connectionFactory());
        redisOperationsSessionRepository.setDefaultMaxInactiveInterval(SESSION_EXPIRATION_TIME);
        return redisOperationsSessionRepository;
    }
}

我们将 redis 2.8.6 与 AWS ElastiCache、spring 框架 4.1.4、spring-data-redis 1.3.0.RELEASE 和 jedis 客户端 2.4.1 一起使用。

知道我们为什么会遇到这个问题吗?

谢谢!

您正在经历 this bug。简而言之,Spring Session 正在尝试为您配置 Redis,而 AWS 禁止配置 Redis(出于安全原因)。

要解决此问题,您可以将 EnableRedisHttpSession 替换为 @Import(Issue124Config.class) 和以下配置:

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.session.ExpiringSession;
import org.springframework.session.SessionRepository;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.session.data.redis.SessionMessageListener;
import org.springframework.session.web.http.HttpSessionStrategy;
import org.springframework.session.web.http.SessionRepositoryFilter;
import org.springframework.util.ClassUtils;

@Configuration
public class Issue124Config {
    @Value("${spring.session.maxInactive ?: 1800}")
    private Integer maxInactiveIntervalInSeconds;

    private HttpSessionStrategy httpSessionStrategy;

    @Bean
    public RedisTemplate<String,ExpiringSession> sessionRedisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, ExpiringSession> template = new RedisTemplate<String, ExpiringSession>();
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setConnectionFactory(connectionFactory);
        return template;
    }

    @Bean
    public RedisOperationsSessionRepository sessionRepository(RedisTemplate<String, ExpiringSession> sessionRedisTemplate) {
        RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(sessionRedisTemplate);
        sessionRepository.setDefaultMaxInactiveInterval(maxInactiveIntervalInSeconds);
        return sessionRepository;
    }

    @Bean
    public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(SessionRepository<S> sessionRepository) {
        SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(sessionRepository);
        if(httpSessionStrategy != null) {
            sessionRepositoryFilter.setHttpSessionStrategy(httpSessionStrategy);
        }
        return sessionRepositoryFilter;
    }

    @Autowired(required = false)
    public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) {
        this.httpSessionStrategy = httpSessionStrategy;
    }
}