Spring Session not using custom RedisTemplate bean - spring

Trying to use a RedisTemplate bean with GenericJackson2JsonRedisSerializer, but while debugging I noticed Spring Session uses a different RedisTemplate instance.
#Configuration
#EnableRedisHttpSession
public class RedisHttpSessionConfig extends
AbstractHttpSessionApplicationInitializer {
#Bean
public JedisConnectionFactory jedisConnectionFactory() {
return new JedisConnectionFactory();
}
#Bean
public RedisTemplate<Object, Object> redisTemplate() {
final RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setConnectionFactory(jedisConnectionFactory());
return template;
}
#Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
When running this, Spring Session seems to use the default JdkSerializationRedisSerializer for hashValues, instead of the desired GenericJackson2JsonRedisSerializer.
Removing extends AbstractHttpSessionApplicationInitializer seems to make Spring use the correct RedisTempplate bean, but then Spring Session isn't wired at all.
Using Spring Session 1.3.3, and spring-boot-starter-data
-redis 1.5.13.
Any idea what I'm missing?

you just need to override default RedisSerializer for spring session like this
#Configuration public class RedisConfig {
#Bean(name="springSessionDefaultRedisSerializer")
public RedisSerializer serializer() {
return new GenericJackson2JsonRedisSerializer();
}

You need to configure and register a RedisTemplate bean named sessionRedisTemplate. This will override the default RedisTemplate instance provided by RedisHttpSessionConfiguration.
You should configure it like:
#Bean
public RedisTemplate<Object, Object> sessionRedisTemplate() {
final RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setConnectionFactory(jedisConnectionFactory());
return template;
}

Related

springboot configuration redis serialization

Why is the error "Could not autowire. No beans of 'RedisConnectionFactory' type found" reported here?
Serialization doesn't work
I used the new way to inject the object and it didn't solve the problem:
#Configuration
public class RedisConfig {
#Resource
private RedisConnectionFactory redisConnectionFactory;
#Bean
public RedisTemplate<Object,Object> redisTemplate(){
RedisTemplate<Object,Object> redisTemplate=new RedisTemplate<>();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setStringSerializer(new StringRedisSerializer());
return redisTemplate;
}
}
When I was implementing redis server I solved this issue by writing code like this
#Configuration
public class RedisConfiguration {
#Bean
#ConditionalOnMissingBean(name = "redisTemplate")
#Primary
public <T> RedisTemplate<String, T> redisTemplate(RedisConnectionFactory connectionFactory) {
final RedisTemplate<String, T> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
ObjectMapper om = new ObjectMapper();
om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
om.registerModule(new JavaTimeModule());
template.setKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer(om));
template.setValueSerializer(new GenericJackson2JsonRedisSerializer(om));
return template;
}
}
This code may be little different from your requirements, but I think if you look closely you can modified according with your needs.

RedisTemplate nullException

There was a problem when I used Springboot to integrate Redis. I want to customize a RedisTemplate, and when I use it, I find that it is always empty and cannot be injected. My code is as follows:
#Configuration
public class RedisConfig {
#Bean(name = "myRedisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
template.setKeySerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
#Autowired
#Qualifier(value = "myRedisTemplate")
private RedisTemplate<String, Object> redisTemplate;
redisTemplate is empty in debug mode.I don't know what went wrong
It could be caused by jedisConnectionFactory do you have such a Bean
#Bean
JedisConnectionFactory jedisConnectionFactory() {
return new JedisConnectionFactory();
}

Multi redis connection issue

I am trying to connect my project with two Redis connection but I got
Consider defining a bean named 'redisTemplate' in your configuration.
I don't know if my code is correct but this is my code config, my spring boot version 2.4.2 :
#Configuration
public class RedisConfiguration {
#Autowired
private EditorialRedisPropertyConfiguration editorialRedisConfiguration;
#Autowired
private ProductRedisPropertyConfiguration productRedisConfiguration;
#Bean(name = "editorialRedisTemplate")
public RedisTemplate<String, ?> editorialRedisTemplate(
#Qualifier(value = "redisEditorialConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, ?> template = new RedisTemplate<>();
template.setConnectionFactory(redisEditorialConnectionFactory());
return template;
}
#Bean(name = "productRedisTemplate")
public RedisTemplate<String, ?> productRedisTemplate(
#Qualifier(value = "redisProductConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, ?> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
#SuppressWarnings("deprecation")
private Jackson2JsonRedisSerializer<Object> initJackson2JsonRedisSerializer() {
. ..
}
#Bean(name = "redisEditorialConnectionFactory")
#Primary
public LettuceConnectionFactory redisEditorialConnectionFactory() {
...
}
#Bean(name = "redisProductConnectionFactory")
#Primary
public LettuceConnectionFactory redisProductConnectionFactory() {
.....
}
}
with application config :
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration
Not quite sure about your application code but this can be fixed by simply creating another bean, given you don't use that you're free to create it from any redis config.
#Bean(name = "productRedisTemplate")
public RedisTemplate<String, ?> redisTemplate(
#Qualifier(value = "redisProductConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, ?> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}

Not picking properties for Redis from property file

I have configured Redis in my spring boot application and I put some properties for that in application.properties file. but its taking default properties (localhost:6379)
here is config
#Configuration
#EnableRedisRepositories("com.demo.redis.repository")
public class RedisDataSourceConfig {
#Bean
public JedisConnectionFactory jedisConnectionFactory() {
log.debug("Create Jedis Connection Factory");
return new JedisConnectionFactory();
}
#Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory());
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new JdkSerializationRedisSerializer());
template.setHashKeySerializer(template.getKeySerializer());
template.setHashValueSerializer(template.getValueSerializer());
return template;
}
#Bean
public RedisTemplate<String, Object> jsonRedisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
redisTemplate.setHashKeySerializer(redisTemplate.getKeySerializer());
redisTemplate.setHashValueSerializer(redisTemplate.getValueSerializer());
return redisTemplate;
}
}
here is my properties in property file
spring.cache.type=redis
spring.redis.host=192.168.10.226
spring.redis.port=6379
spring.cache.redis.time-to-live=600000
I have used RedisStandaloneConfiguration to set properties. it's working fine now
#Bean
JedisConnectionFactory jedisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName("localhost");
redisStandaloneConfiguration.setPort(6379);
redisStandaloneConfiguration.setDatabase(0);
redisStandaloneConfiguration.setPassword(RedisPassword.of("password"));
JedisClientConfigurationBuilder jedisClientConfiguration = JedisClientConfiguration.builder();
jedisClientConfiguration.connectTimeout(Duration.ofSeconds(60));// 60s connection timeout
JedisConnectionFactory jedisConFactory = new JedisConnectionFactory(redisStandaloneConfiguration,
jedisClientConfiguration.build());
return jedisConFactory;
}
Add the PropertySource Annotation with your config
#Configuration
#EnableRedisRepositories("com.demo.redis.repository")
#PropertySource("classpath:application.properties")
public class RedisDataSourceConfig {
#Bean
public JedisConnectionFactory jedisConnectionFactory() {
log.debug("Create Jedis Connection Factory");
return new JedisConnectionFactory();
}
#Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory());
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new JdkSerializationRedisSerializer());
template.setHashKeySerializer(template.getKeySerializer());
template.setHashValueSerializer(template.getValueSerializer());
return template;
}
#Bean
public RedisTemplate<String, Object> jsonRedisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
redisTemplate.setHashKeySerializer(redisTemplate.getKeySerializer());
redisTemplate.setHashValueSerializer(redisTemplate.getValueSerializer());
return redisTemplate;
}
}
Instead of using the #Bean annotation, you should use #Autowired for JedisConnectionFactory. Use the following code:
#Autowired
private JedisConnectionFactory jedisConnectionFactory;
And then in your redisTemplate() method just call:
template.setConnectionFactory(jedisConnectionFactory);
Now, jedisConnectionFactory will use your application.properties as long as it is available in the standard path: src/main/resources.

SpringBoot Elasticache JedisMovedDataException: MOVED

Trying to use SpringBoot with SpringData with Elasticache:
application.properties:
spring.redis.host=XXXX-dev.XXXX.clusXXXcfg.XXX.cache.amazonaws.com
spring.redis.port=6379
CacheConfiguration:
#Configuration
#PropertySource("classpath:application.properties")
public class CacheConfiguration {
#Value("${spring.redis.host}")
private String redisHostName;
#Bean
public RedisTemplate<String, Company> redisTemplate() {
RedisTemplate<String, Company> template = new RedisTemplate();
template.setConnectionFactory(jedisConnectionFactory());
return template;
}
#Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName(redisHostName);
factory.setUsePool(true);
return factory;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Service call:
#Autowired
RedisTemplate<String, Company> redisTemplate;
private ValueOperations valueOperations;
#PostConstruct
private void init() {
valueOperations = redisTemplate.opsForValue();
}
#Override
public String createOtp(Company company) {
String token = UUID.randomUUID().toString();
valueOperations.set(token, company);
valueOperations.getOperations().expire(token, 5, TimeUnit.MINUTES);
return token;
}
Error:
org.springframework.data.redis.ClusterRedirectException: Redirect: slot 7228 to 10...:6379.*
redis.clients.jedis.exceptions.JedisMovedDataException: MOVED 7228 10...:6379.*
The question is - what is wrong with configuration?
You're running your Elasticache in Redis Cluster mode (only Redis Cluster responds with MOVED) but the connection factory is configured in standalone mode.
Spring Boot can auto-configure all the things you've set up manually for you. Basically, remove your CacheConfiguration class (or at least remove the majority of code):
#Configuration
public class CacheConfiguration {
#Bean
public RedisTemplate<String, Company> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Company> template = new RedisTemplate();
template.setConnectionFactory(connectionFactory);
return template;
}
}
And then configure the following properties in your application.properties file:
spring.redis.cluster.nodes=<node_host>:<port> # Comma-separated list of "host:port" pairs to bootstrap from.
Spring Boot loads application.properties by default and the Redis auto-config configures a RedisTemplate<Object, Object> bean by default. Specializing beans is a valid use-case – do not duplicate what's already provided by the auto-config, especially if you want to achieve what auto-config does.
See also:
Common application properties
Externalized Configuration

Resources