Spring Redis - Read configuration from application.properties file
Asked Answered
I

10

32

I have Spring Redis working using spring-data-redis with all default configuration likes localhost default port and so on.

Now I am trying to make the same configuration by configuring it in application.properties file. But I cannot figure out how should I create beans exactly that my property values are read.

Redis Configuration File

@EnableRedisHttpSession
@Configuration
public class SpringSessionRedisConfiguration {

@Bean
JedisConnectionFactory connectionFactory() {
    return new JedisConnectionFactory();
}

@Autowired
@Bean
RedisCacheManager redisCacheManager(final StringRedisTemplate stringRedisTemplate) {
    return new RedisCacheManager(stringRedisTemplate);
}

@Autowired
@Bean
StringRedisTemplate template(final RedisConnectionFactory connectionFactory) {
    return new StringRedisTemplate(connectionFactory);
}
}

Standard Parameters in application.properties

spring.redis.sentinel.master=themaster

spring.redis.sentinel.nodes=192.168.188.231:26379

spring.redis.password=12345

What I tried,

  1. I can possibly use @PropertySource and then inject @Value and get the values. But I don't want to do that as those properties are not defined by me but are from Spring.
  2. In this documentation Spring Redis Documentation, it only says that it can be configured using properties but doesn't show concrete example.
  3. I also went through Spring Data Redis API classes, and found that RedisProperties should help me, but still cannot figure out how exactly to tell Spring to read from properties file.
Incapacious answered 10/12, 2015 at 11:50 Comment(1)
currently doing by using @Value annotation, any better suggestionsIncapacious
D
42

You can use @PropertySource to read options from application.properties or other property file you want. Please look PropertySource usage example and working example of usage spring-redis-cache. Or look at this small sample:

@Configuration
@PropertySource("application.properties")
public class SpringSessionRedisConfiguration {

    @Value("${redis.hostname}")
    private String redisHostName;

    @Value("${redis.port}")
    private int redisPort;

    @Bean
    public static PropertySourcesPlaceholderConfigurer    propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    JedisConnectionFactory jedisConnectionFactory() {
        JedisConnectionFactory factory = new JedisConnectionFactory();
        factory.setHostName(redisHostName);
        factory.setPort(redisPort);
        factory.setUsePool(true);
        return factory;
    }

    @Bean
    RedisTemplate<Object, Object> redisTemplate() {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
        redisTemplate.setConnectionFactory(jedisConnectionFactory());
        return redisTemplate;
    }

    @Bean
    RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate());
        return redisCacheManager;
    }
}

In present time (december 2015) the spring.redis.sentinel options in application.properties has limited support of RedisSentinelConfiguration:

Please note that currently only Jedis and lettuce Lettuce support Redis Sentinel.

You may read more about this in official documentation.

Derry answered 17/12, 2015 at 7:33 Comment(4)
Thank you for answering, this is the approach I was using before I asked this question. But let me give an example, spring-boot-starter-data-jpa, here if you want to configure data source, you simply have to set spring.datasource.url property and spring does its magic. And because its one of the standard application properties (docs.spring.io/spring-boot/docs/current/reference/html/…). We don't have to write any specific logic for reading that, then there should be some way to do this for Redis as well, may be by the way beans are created.Incapacious
Yes, i understand. But the sentinel properties is not supported in default application.properties. So you should use the way i mention above.Derry
RedisSentinelConfiguration has a constructor with PropertySource, and this constructor already has a logic for reading those two sentinal specific properties. I am trying to figure out now, how can I pass a PropertySource of my application.propertiesIncapacious
Yes it has and see the code you are mention. And yes, currently RedisSentinelConfiguration doesn't supported for all types of application. Please look at docs.spring.io/spring-data/redis/docs/current/reference/html (Redis Sentinel Support). On current stage just Jedis and Lettuce support Redis Sentinel with configuring throw application.properties. But not any application used spring-data-redis.Derry
H
15

Upon looking deeper I found this, could it be what you are looking for?

# REDIS (RedisProperties)
spring.redis.database=0 # Database index used by the connection factory.
spring.redis.host=localhost # Redis server host.
spring.redis.password= # Login password of the redis server.
spring.redis.pool.max-active=8 # Max number of connections that can be allocated by the pool at a given time. Use a negative value for no limit.
spring.redis.pool.max-idle=8 # Max number of "idle" connections in the pool. Use a negative value to indicate an unlimited number of idle connections.
spring.redis.pool.max-wait=-1 # Maximum amount of time (in milliseconds) a connection allocation should block before throwing an exception when the pool is exhausted. Use a negative value to block indefinitely.
spring.redis.pool.min-idle=0 # Target for the minimum number of idle connections to maintain in the pool. This setting only has an effect if it is positive.
spring.redis.port=6379 # Redis server port.
spring.redis.sentinel.master= # Name of Redis server.
spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs.
spring.redis.timeout=0 # Connection timeout in milliseconds. 

Refernce:https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html Searchterm Redis

From what I can see the values already exist and are defined as

spring.redis.host=localhost # Redis server host.
spring.redis.port=6379 # Redis server port.

if you want to create your own properties you can look at my previous post in this thread.

Hannigan answered 19/12, 2015 at 22:32 Comment(1)
Well this works only for properties mentioned in your link, my question was specific to the properties related to sentinel configuration. And sentinel are also default spring properties, but still framework doesn't read them and connection is not established.Incapacious
A
13

This works for me :

@Configuration
@EnableRedisRepositories
public class RedisConfig {

    @Bean
    public JedisConnectionFactory jedisConnectionFactory() {
        RedisProperties properties = redisProperties();
        RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
        configuration.setHostName(properties.getHost());
        configuration.setPort(properties.getPort());

        return new JedisConnectionFactory(configuration);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        final RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(jedisConnectionFactory());
        template.setValueSerializer(new GenericToStringSerializer<>(Object.class));
        return template;
    }

    @Bean
    @Primary
    public RedisProperties redisProperties() {
        return new RedisProperties();
    }

}

and properties file :

spring.redis.host=localhost
spring.redis.port=6379
Algebraic answered 11/10, 2018 at 17:10 Comment(1)
This works, just a small remark: the @Primary is needed here, since the redisProperties method creates a duplicate bean that, while works, is redundant. You can just @Autowired the existing RedisProperties (or use constructor injection, of course), and remove that @Bean.Mcmahon
H
2

I found this within the spring boot doc section 24 paragraph 7

@Component
@ConfigurationProperties(prefix="connection")
public class ConnectionSettings {

    private String username;

    private InetAddress remoteAddress;

    // ... getters and setters

} 

Properties can then be modified via connection.property

Reference link: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties

Hannigan answered 19/12, 2015 at 16:53 Comment(2)
I will try this and update you, if this is what I really want.Incapacious
Well I didn't try this approach, as approach marked as answer works well for me, but thanks for answering may be it helps somebody elseIncapacious
O
2

Here is an elegant solution to solve your issue :

@Configuration
@PropertySource(name="application", value="classpath:application.properties")
public class SpringSessionRedisConfiguration {

    @Resource
    ConfigurableEnvironment environment;

    @Bean
    public PropertiesPropertySource propertySource() {
        return (PropertiesPropertySource) environment.getPropertySources().get("application");
    }

    @Bean
    public JedisConnectionFactory jedisConnectionFactory() {
        return new JedisConnectionFactory(sentinelConfiguration(), poolConfiguration());
    }

    @Bean
    public RedisSentinelConfiguration sentinelConfiguration() {
        return new RedisSentinelConfiguration(propertySource());
    }

    @Bean
    public JedisPoolConfig poolConfiguration() {
        JedisPoolConfiguration config = new JedisPoolConfiguration();
        // add your customized configuration if needed
        return config;
    }

    @Bean
    RedisTemplate<Object, Object> redisTemplate() {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
        redisTemplate.setConnectionFactory(jedisConnectionFactory());
        return redisTemplate;
    }

    @Bean
    RedisCacheManager cacheManager() {
        return new RedisCacheManager(redisTemplate());
    }

}

so, to resume :

  • add a specific name for the @PropertySource
  • inject a ConfigurableEnvironment instead of Environment
  • get the PropertiesPropertySource in your ConfigurableEnvironment using the name you mentioned on your @PropertySource
  • Use this PropertySource object to construct your RedisSentinelConfiguration object
  • Don't forget to add 'spring.redis.sentinel.master' and 'spring.redis.sentinel.nodes' properties in you property file

Tested in my workspace, Regards

Olive answered 16/6, 2017 at 12:57 Comment(1)
This works and answers the question of "how do I pass a PropertySource as a parameter to the RedisSentinelConfiguration constructor - thanks!Lifeblood
D
1

Property prefix spring.redis is no longer valid currently spring uses: spring.data.redis prefix

Deaf answered 3/3, 2023 at 15:54 Comment(0)
M
0

You can use the ResourcePropertySource to generate a PropertySource object.

PropertySource propertySource = new ResourcePropertySource("path/to/your/application.properties");

Then pass it to the constructor of the RedisSentinelConfiguration.

Mainsail answered 15/6, 2016 at 5:41 Comment(0)
G
-1

I think this what you are looking for http://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot.html

Giaour answered 20/12, 2015 at 5:21 Comment(1)
Well this works only for properties mentioned in your link, my question was specific to the properties related to sentinel configuration. And sentinel are also default spring properties, but still framework doesn't read them and connection is not established.Incapacious
L
-2

Use @DirtiesContext(classMode = classmode.AFTER_CLASS) at each test class. This will surely work for you.

Latashalatashia answered 25/6, 2018 at 20:43 Comment(1)
Suggest to use annotation which is targeted for Spring tests?Trengganu
T
-3
@Autowired
private JedisConnectionFactory connectionFactory;

@Bean
JedisConnectionFactory connectionFactory() {
    return connectionFactory
}
Thesda answered 19/11, 2016 at 23:35 Comment(1)
This is not an answerCaulis

© 2022 - 2024 — McMap. All rights reserved.