Multi redis connection issue - spring

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;
}

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();
}

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

Cache with redis cache manager, redisTemplate and multiple serializers

I need to cache multiple types like:
public Country findCountry(String countryName)
and:
public List<Destination> findAllDestinations(String countryName)
I am using RedisCacheManager and RedisTemplate only support only one serializer.
It is solved now after some research.
change spring-data-redis to 1.4.2.RELEASE
extend RedisCacheManager with your class with cache map to serializer (cacheName->serializer) and caches names
overrides the getCache method(Cache getCache(String name)) and based on cache name, set the serializer name in the redis template
use your customized cache manager
Example -
public class CustomRedisCacheManager extends RedisCacheManager
{
public static final String CACHE_NAME_DEFAULT = "default";
public static final String CACHE_NAME_COUNTRY = "country";
public static final String CACHE_NAME_DESTINATIONS = "destinations";
private Map<String, RedisCache> redisCaches = new HashMap<>();
public CustomRedisCacheManager(Map<String, RedisTemplate> redisTemplates)
{
super(redisTemplates.get(CACHE_NAME_DEFAULT), redisTemplates.keySet());
redisTemplates.keySet().stream().forEach(cacheName -> redisCaches.put(cacheName, new RedisCache(cacheName, null, redisTemplates.get(cacheName), 0)));
}
#Override
public Cache getCache(String cacheName)
{
return redisCaches.get(cacheName);
}
}
#Configuration
#EnableCaching
public class RedisConfiguration extends CachingConfigurerSupport
{
#Bean
public JedisConnectionFactory jedisConnectionFactory()
{
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName(redisHostName);
factory.setPort(redisPort);
factory.setTimeout(100);
return factory;
}
#Bean
public CacheManager cacheManager()
{
Map<String, RedisTemplate> templates = new HashMap<>();
templates.put(CACHE_NAME_DEFAULT, getDefaultRedisTemplate());
templates.put(CACHE_NAME_COUNTRY, getMetadataRedisTemplate());
templates.put(CACHE_NAME_DESTINATIONS, getDestinationsRedisTemplate());
SabreRedisCacheManager sabreRedisCacheManager = new SabreRedisCacheManager(templates);
return sabreRedisCacheManager;
}
#Bean
public RedisTemplate<Object, Object> getDefaultRedisTemplate()
{
return getBaseRedisTemplate();
}
#Bean
public RedisTemplate<Object, Object> getCountryRedisTemplate()
{
RedisTemplate<Object, Object> redisTemplate = getBaseRedisTemplate();
redisTemplate.setValueSerializer(jsonRedisSerializer(Country.class));
return redisTemplate;
}
#Bean
public RedisTemplate<Object, Object> getDestinationsRedisTemplate()
{
RedisTemplate<Object, Object> redisTemplate = getBaseRedisTemplate();
redisTemplate.setValueSerializer(jsonRedisSerializer(TypeFactory.defaultInstance().constructCollectionType(List.class, Destination.class)));
return redisTemplate;
}
private RedisTemplate<Object, Object> getBaseRedisTemplate()
{
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
redisTemplate.setKeySerializer(stringRedisSerializer());
redisTemplate.setHashKeySerializer(stringRedisSerializer());
redisTemplate.setValueSerializer(jsonRedisSerializer(Object.class));
return redisTemplate;
}
private Jackson2JsonRedisSerializer jsonRedisSerializer(Class type)
{
return jsonRedisSerializer(TypeFactory.defaultInstance().constructType(type));
}
private Jackson2JsonRedisSerializer jsonRedisSerializer(JavaType javaType)
{
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(javaType);
jackson2JsonRedisSerializer.setObjectMapper(new JsonObjectMapper());
return jackson2JsonRedisSerializer;
}
}

Resources