【问题标题】:Spring Redis - Read configuration from application.properties fileSpring Redis - 从 application.properties 文件中读取配置
【发布时间】:2016-03-16 01:03:16
【问题描述】:

我让 Spring Redis 使用 spring-data-redis 和所有默认配置(如 localhost 默认 port 等)工作。

现在我正在尝试通过在application.properties 文件中进行配置来进行相同的配置。但我无法弄清楚我应该如何创建完全读取我的属性值的 bean。

Redis 配置文件

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

application.properties 中的标准参数

spring.redis.sentinel.master=themaster

spring.redis.sentinel.nodes=192.168.188.231:26379

spring.redis.password=12345

我试过了,

  1. 我可以使用@PropertySource 然后注入@Value 并获取值。但我不想这样做,因为这些属性不是我定义的,而是来自 Spring。
  2. 在本文档Spring Redis Documentation 中,它只说可以使用属性进行配置,但没有显示具体示例。
  3. 我还浏览了 Spring Data Redis API 类,发现 RedisProperties 应该可以帮助我,但仍然无法弄清楚如何告诉 Spring 从属性文件中读取。

【问题讨论】:

  • 目前正在使用@Value注解,有更好的建议

标签: java spring configuration redis


【解决方案1】:

您可以使用@PropertySource 从 application.properties 或您想要的其他属性文件中读取选项。请查看PropertySource usage example 和工作example of usage spring-redis-cache。或者看看这个小样本:

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

目前(2015 年 12 月application.properties 中的 spring.redis.sentinel 选项对 RedisSentinelConfiguration 的支持有限:

请注意,目前只有 Jedis 和 lettuce Lettuce 支持 Redis Sentinel。

您可以在official documentation 中了解更多相关信息。

【讨论】:

  • 感谢您的回答,这是我在问这个问题之前使用的方法。但让我举个例子,spring-boot-starter-data-jpa,如果你想配置数据源,你只需要设置spring.datasource.url属性,spring就会发挥它的魔力。并且因为它是标准应用程序属性之一 (docs.spring.io/spring-boot/docs/current/reference/html/…)。我们不必编写任何特定的逻辑来读取它,那么 Redis 也应该有一些方法可以做到这一点,可能是通过创建 bean 的方式。
  • 是的,我明白了。但在默认的 application.properties 中不支持哨兵属性。所以你应该使用我上面提到的方式。
  • RedisSentinelConfiguration 有一个带有PropertySource 的构造函数,并且这个构造函数已经具有读取这两个特定属性的逻辑。我现在想弄清楚,我怎样才能通过我的PropertySourceapplication.properties
  • 是的,看看你提到的代码。是的,目前RedisSentinelConfiguration 并不支持所有类型的应用程序。请查看docs.spring.io/spring-data/redis/docs/current/reference/html(Redis Sentinel 支持)。在当前阶段,只有 Jedis 和 Lettuce 通过配置 throw application.properties 来支持 Redis Sentinel。但没有任何应用程序使用 spring-data-redis。
【解决方案2】:

经过深入研究,我发现了这个,这可能是您要找的吗?

# 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. 

参考:https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html搜索词Redis

据我所知,这些值已经存在并被定义为

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

如果您想创建自己的属性,可以查看我在此线程中的上一篇文章。

【讨论】:

  • 这仅适用于您的链接中提到的属性,我的问题是特定于与sentinel 配置相关的属性。并且sentinel 也是默认的spring 属性,但是框架仍然没有读取它们并且没有建立连接。
【解决方案3】:

这对我有用:

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

}

和属性文件:

spring.redis.host=localhost
spring.redis.port=6379

【讨论】:

  • 这行得通,只是一个小注释:这里需要@Primary,因为redisProperties 方法创建了一个重复的bean,虽然有效,但它是多余的。你可以只 @Autowired 现有的 RedisProperties (或者使用构造函数注入,当然),然后删除 @Bean
【解决方案4】:

我在 Spring Boot 文档第 24 节第 7 段中找到了这个

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

    private String username;

    private InetAddress remoteAddress;

    // ... getters and setters

} 

然后可以通过 connection.property 修改属性

参考链接:https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties

【讨论】:

  • 如果这是我真正想要的,我会试试这个并更新你。
  • 好吧,我没有尝试这种方法,因为标记为答案的方法对我来说效果很好,但是感谢您的回答可能对其他人有帮助
【解决方案5】:

这里有一个优雅的解决方案来解决您的问题:

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

}

所以,继续:

  • 为@PropertySource 添加特定名称
  • 注入 ConfigurableEnvironment 而不是 Environment
  • 使用您在@PropertySource 中提到的名称在您的 ConfigurableEnvironment 中获取 PropertiesPropertySource
  • 使用此 PropertySource 对象来构造您的 RedisSentinelConfiguration 对象
  • 不要忘记在属性文件中添加“spring.redis.sentinel.master”和“spring.redis.sentinel.nodes”属性

在我的工作区测试, 问候

【讨论】:

  • 这有效并回答了“如何将 PropertySource 作为参数传递给 RedisSentinelConfiguration 构造函数 - 谢谢!
【解决方案6】:

您可以使用 ResourcePropertySource 来生成 PropertySource 对象。

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

然后将其传递给 RedisSentinelConfiguration 的构造函数。

【讨论】:

    【解决方案7】:

    【讨论】:

    • 这仅适用于您的链接中提到的属性,我的问题是特定于与sentinel 配置相关的属性。并且sentinel 也是默认的spring 属性,但是框架仍然没有读取它们并且没有建立连接。
    【解决方案8】:
    @Autowired
    private JedisConnectionFactory connectionFactory;
    
    @Bean
    JedisConnectionFactory connectionFactory() {
        return connectionFactory
    }
    

    【讨论】:

    • 这不是答案
    【解决方案9】:

    在每个测试类中使用@DirtiesContext(classMode = classmode.AFTER_CLASS)。这肯定对你有用。

    【讨论】:

    • 建议使用针对 Spring 测试的注解?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-17
    • 1970-01-01
    • 2018-01-07
    • 2018-02-25
    • 2018-09-15
    相关资源
    最近更新 更多