在我们开发项目过程中,使用redis时,经常遇到需要在开发、测试版本中切换redis的集群或单机环境参数,如果把redis的环境参数写死在程序代码中或只有一项目配置参数,那么在发布测试版本时就要来回的修改redis的配置参数并重新打包,非常的麻烦。
利用nacos的配置中心,我们可以让软件包动态地中nacos配置中心中读取redis的集群或单机环境配置参数,不过需要我们进行一定程度的程序改造。
1、首先在pom.xml中导入redis包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.7</version>
</dependency>
2、利用spring提供的@ConditionalOnProperty标签动态从nacos配置中心读取redis环境参数
package com.acorn.core.redis;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.ReadMode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import lombok.extern.log4j.Log4j2;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.util.Pool;
@Configuration
@EnableAutoConfiguration
@ConditionalOnProperty(value = "spring.redis.enabled",havingValue = "true",matchIfMissing=true)
@Log4j2
public class RedisConfig {
@Autowired
RedisProperties redisProperties;
@Bean
public JedisPoolConfig getRedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(redisProperties.getJedis().getPool().getMaxIdle());
jedisPoolConfig.setMaxIdle(redisProperties.getJedis().getPool().getMinIdle());
jedisPoolConfig.setMaxWaitMillis(redisProperties.getJedis().getPool().getMaxWait().getSeconds());
return jedisPoolConfig;
}
@Bean
@ConditionalOnProperty(value = "spring.redis.mode",havingValue = "sentinel")
public Pool<Jedis> getJedisPoolModeSentinel() {
Set<String> newNodes = new HashSet<>();
for (int i = 0; i < redisProperties.getSentinel().getNodes().size(); i++) {
newNodes.add(redisProperties.getSentinel().getNodes().get(i));
}
log.info("###spring.redis.mode:sentinel,ip:{}",newNodes);
// 创建连接池
JedisSentinelPool pool = new JedisSentinelPool(redisProperties.getSentinel().getMaster(), newNodes, getRedisPoolConfig(),
Long.valueOf(redisProperties.getTimeout().toMillis()).intValue(), redisProperties.getPassword(), redisProperties.getDatabase());
return pool;
}
@Bean
@ConditionalOnProperty(value = "spring.redis.mode",havingValue = "standalone")
public Pool<Jedis> getJedisPoolModeStandalone() {
JedisPool pool = new JedisPool(getRedisPoolConfig(), redisProperties.getHost(), redisProperties.getPort(),
Long.valueOf(redisProperties.getTimeout().toMillis()).intValue(), redisProperties.getPassword());
log.info("###spring.redis.mode:standalone,ip:{}",redisProperties.getHost());
return pool;
}
/**
* @Description: 哨后模式:JedisConnectionFactory
* @date 2022年10月27日 下午4:57:06
* @param jedisPoolConfig
* @return
*/
@Bean
@ConditionalOnProperty(value = "spring.redis.mode",havingValue = "sentinel")
public JedisConnectionFactory jedisConnectionFactoryModeSentinel(JedisPoolConfig jedisPoolConfig) {
RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();
redisSentinelConfiguration.setMaster(redisProperties.getSentinel().getMaster());
redisSentinelConfiguration.setDatabase(redisProperties.getDatabase());
redisSentinelConfiguration.setSentinels(getSentinelNodes());
String password = redisProperties.getPassword();
redisSentinelConfiguration.setPassword(RedisPassword.of(password.toCharArray()));
JedisConnectionFactory objJedisConnectionFactory = new JedisConnectionFactory(redisSentinelConfiguration, jedisPoolConfig);
return objJedisConnectionFactory;
}
/**
* @Description: 单机模式:JedisConnectionFactory
* @param jedisPoolConfig
* @return
*/
@Bean("redisConnectionFactory")
@ConditionalOnProperty(value = "spring.redis.mode",havingValue = "standalone")
public JedisConnectionFactory jedisConnectionFactoryModeStandalone(JedisPoolConfig jedisPoolConfig) {
RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration();
standaloneConfiguration.setDatabase(redisProperties.getDatabase());
standaloneConfiguration.setHostName(redisProperties.getHost());
standaloneConfiguration.setPassword(redisProperties.getPassword());
standaloneConfiguration.setPort(redisProperties.getPort());
JedisConnectionFactory objJedisConnectionFactory = new JedisConnectionFactory(standaloneConfiguration);
return objJedisConnectionFactory;
}
@Bean
@ConditionalOnProperty(value = "spring.redis.mode",havingValue = "sentinel")
public RedissonClient createSentinelRedissonClient() {
Config config = new Config();
List<String> newNodes = new ArrayList<>();
for (int i = 0; i < redisProperties.getSentinel().getNodes().size(); i++) {
newNodes.add("redis://" + redisProperties.getSentinel().getNodes().get(i));
}
config.useSentinelServers()
.addSentinelAddress(newNodes.toArray(new String[0]))
.setMasterName(this.redisProperties.getSentinel().getMaster())
.setPassword(this.redisProperties.getPassword())
.setReadMode(ReadMode.SLAVE)
.setTimeout(60000)
.setRetryAttempts(3)
.setRetryInterval(60000)
//**此项务必设置为redisson解决之前bug的timeout问题关键*****
.setPingConnectionInterval(60000)
.setDatabase(redisProperties.getDatabase());
return Redisson.create(config);
}
@Bean
@ConditionalOnProperty(value = "spring.redis.mode",havingValue = "standalone")
public RedissonClient createStandaloneRedissonClient() {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://" +this.redisProperties.getHost()+":"+this.redisProperties.getPort())
.setPassword(this.redisProperties.getPassword())
.setTimeout(60000)
.setRetryAttempts(3)
.setRetryInterval(60000)
//**此项务必设置为redisson解决之前bug的timeout问题关键*****
.setPingConnectionInterval(60000);
return Redisson.create(config);
}
@Bean
public Set<RedisNode> getSentinelNodes() {
Set<RedisNode> nodos = new HashSet<>();
for (int i = 0; i < redisProperties.getSentinel().getNodes().size(); i++) {
String[] split = redisProperties.getSentinel().getNodes().get(i).split(":");
nodos.add(new RedisNode(split[0], Integer.parseInt(split[1])));
}
return nodos;
}
}
3、修改原redisService,添加@ConditionalOnProperty标签,
标签与RedisConfig 保持一致即可。
@Service
@ConditionalOnProperty(value = "spring.redis.enabled",havingValue = "true",matchIfMissing=true)
public class DefaultJedisService implements IJedisService{
//.....省略redis操作代码
}
4、在nacos中添加redis参数配置
redis参数内容:
spring:
redis:
enabled: true
mode: standalone ##启用集群时这个参数为sentinel
password: aaaaa
timeout: 10000
jedis:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 1
sentinel:
nodes: ip:6379,ip:6379,ip:6379
master: mymaster
database: 6
host: ip
port: 6379
在本例中启用集群时只需将mode: standalone
改为mode: sentinel即可,无需更改其它参数
样例下载地址【redis-demo:spring-cloud-nacos动态配置】
文章虽然短,但确实很实用,你不加个关注再走吗