I need to have a spring redis configured to save my sessions using spring redis sessions and other for private stuff.
Currently my project is injecting my dependencies and context and between them there is a redis configuration already with the RedisConnectionFactory defined.
To make my new connection work I have to set it as primary="true" just as this solution .
But I am wondering if with that I am going to change the other beans? I dont want to override all others that invoke the connectionFactory , what can I do?
Hi @jpganz - if you register a RedisOperations bean named sessionRedisTemplate the @EnableRedisHttpSession configuration will pick it up and inject into RedisOperationsSessionRepository.
Take a look at RedisHttpSessionConfiguration:
@Bean
public RedisOperationsSessionRepository sessionRepository(
@Qualifier("sessionRedisTemplate") RedisOperations<Object, Object> sessionRedisTemplate,
ApplicationEventPublisher applicationEventPublisher) {
RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(
sessionRedisTemplate);
// ...
return sessionRepository;
}
So you just need to ensure this RedisOperations bean named sessionRedisTemplate is configured with RedisConnectionFactory of your choice.
`import java.io.Serializable;
import java.lang.reflect.Method;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
@PropertySource(value = "classpath:RedisServer.properties")
@EnableRedisHttpSession(maxInactiveIntervalInSeconds=1800, redisNamespace="gps-web")
public class RedisConfig implements CachingConfigurer {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis2.host}")
private String host2;
@Value("${spring.redis2.port}")
private int port2;
@Value("${spring.redis2.password}")
private String password2;
@Value("${spring.redis3.host}")
private String host3;
@Value("${spring.redis3.port}")
private int port3;
@Value("${spring.redis3.password}")
private String password3;
@Bean
public KeyGenerator workKeyGenerator(){
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
@Bean(name = "CommandRedisServer1")
@Primary
public RedisConnectionFactory cmd1RedisConnectionFactory(){
JedisConnectionFactory redisConnectionFactory=new JedisConnectionFactory();
redisConnectionFactory.setHostName(host);
redisConnectionFactory.setPort(port);
redisConnectionFactory.setPassword(password);
redisConnectionFactory.setUsePool(true);
return redisConnectionFactory;
}
@Bean(name = "CommandRedisServer2")
public RedisConnectionFactory cmd2RedisConnectionFactory(){
JedisConnectionFactory redisConnectionFactory=new JedisConnectionFactory();
redisConnectionFactory.setHostName(host2);
redisConnectionFactory.setPort(port2);
redisConnectionFactory.setPassword(password2);
redisConnectionFactory.setUsePool(true);
return redisConnectionFactory;
}
@Bean(name = "CommandRedisServer3")
public RedisConnectionFactory cmd3RedisConnectionFactory(){
JedisConnectionFactory redisConnectionFactory=new JedisConnectionFactory();
redisConnectionFactory.setHostName(host3);
redisConnectionFactory.setPort(port3);
redisConnectionFactory.setPassword(password3);
redisConnectionFactory.setUsePool(true);
return redisConnectionFactory;
}
@Bean(name = "RedisTemplateForNO1")
public RedisTemplate<String, Serializable> stringRedisTemplate(@Qualifier(value = "CommandRedisServer1") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Serializable> template = new RedisTemplate<String, Serializable>();
template.setConnectionFactory(redisConnectionFactory);
template.afterPropertiesSet();
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Bean(name = "RedisTemplateForNO2")
public RedisTemplate<String, Serializable> redisTemplate(@Qualifier(value = "CommandRedisServer2")RedisConnectionFactory factory) {
RedisTemplate<String, Serializable> template = new RedisTemplate<String, Serializable>();
template.setConnectionFactory(factory);
template.afterPropertiesSet();
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Bean(name = "RedisTemplateForNO3")
public RedisTemplate<String, Serializable> redisServerTemplate(@Qualifier(value = "CommandRedisServer3")RedisConnectionFactory factory1) {
RedisTemplate<String, Serializable> template = new RedisTemplate<String, Serializable>();
template.setConnectionFactory(factory1);
template.afterPropertiesSet();
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Bean
public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
return new RedisCacheManager(redisTemplate);
}
@Override
public CacheManager cacheManager() {
return null;
}
@Override
public KeyGenerator keyGenerator() {
return null;
}
@Override
public CacheResolver cacheResolver() {
return null;
}
@Override
public CacheErrorHandler errorHandler() {
return null;
}
}`
@Triswuting We've recently added @SpringSessionRedisConnectionFactory qualifier annotation to provide better support for this use case - see #864 and #887.
@Triswuting We've recently added
@SpringSessionRedisConnectionFactoryqualifier annotation to provide better support for this use case - see #864 and #887.
Nice solution. It's work. Thanks
@Triswuting We've recently added
@SpringSessionRedisConnectionFactoryqualifier annotation to provide better support for this use case - see #864 and #887.
Does think this fix the issue. It's not easy to use in real project.
To use @SpringSessionRedisConnectionFactory, we need to create a primary connectionFactory for common use first which cause that we can not benifit from the redis auto-configuration. User need to config sentinal/cluster themselves.
Why not just move redis configuration properties to prefix spring.session.redis to isolate it from default redis config properties. Those two kind data is so different that i think most project will choose to seperate them.
@IamFive Spring Session does not provide properties mapping to conditional beans. This is a Boot feature. You can always create your own Bean with the properties of your choice ensuring to qualify the bean you are creating
@rwinch Spring session connectionFactory is confict with the default data-redis if we create and expose it directly (correct me if i am wrong). And if we want to implement a reusable connectionFactory for spring-session, we need to copy spring-redis-auto-configuration code to our project.. this is really ugly. So, my suggest is "implement a seperate connectFactory in spring-session-data-redis directly". Using a seperate redis(even a isolate database of redis) is more reasonable in most project then why not provide it directly.
Discussing if Spring Boot should support creating separate Redis connections is not appropriate here as it is not our code base (we cannot make the change). If you want to discuss creating that feature, you need to log it with Spring Boot's issue tracker
Spring session connectionFactory is confict with the default data-redis if we create and expose it directly (correct me if i am wrong).
You would create both connections in your project.
Using a seperate redis(even a isolate database of redis) is more reasonable in most project then why not provide it directly.
Perhaps this is what you want, but it is not empirically true for all projects.
I see, thanks for the response.
Most helpful comment
@Triswuting We've recently added
@SpringSessionRedisConnectionFactoryqualifier annotation to provide better support for this use case - see #864 and #887.