【AI教我烧操作】监听 Nacos 配置变化实现动态切换 Redis 连接池

会问问题的小明:如何通过监听 Nacos 配置变化实现动态切换 Redis 连接池?

AI大佬: 废话少说,上操作

以下是一个示例代码,可以通过监听 Nacos 配置变化实现动态切换 Redis 连接池:

示例代码

@EnableDiscoveryClient
@SpringBootApplication
public class RedisClusterDemoApplication {

    private static final Logger LOGGER = LoggerFactory.getLogger(RedisClusterDemoApplication.class);

    private static final String GROUP_ID = "DEFAULT_GROUP";
    private static final String REDIS_CONFIG_DATA_ID = "redis-config";
    private static final String REDIS_SENTINEL_CONFIG_DATA_ID = "redis-sentinel-config";
    private static final String REDIS_CLUSTER_CONFIG_DATA_ID = "redis-cluster-config";

    // 通过 NacosConfigListener 监听配置变化并重新初始化连接池
    @Value("${spring.cloud.nacos.config.server-addr}")
    private String nacosServerAddr;

    @Value("${spring.cloud.nacos.config.namespace}")
    private String nacosNamespace;

    @Value("${spring.cloud.nacos.config.username}")
    private String nacosUsername;

    @Value("${spring.cloud.nacos.config.password}")
    private String nacosPassword;

    @Value("${spring.cloud.nacos.config.prefix}")
    private String nacosConfigPrefix;

    private RedisConnectionFactory redisConnectionFactory;

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @Autowired
    private RedisConnectionFactory redisSentinelConnectionFactory;

    @Autowired
    private RedisConnectionFactory redisClusterConnectionFactory;

    public static void main(String[] args) {
        SpringApplication.run(RedisClusterDemoApplication.class, args);
    }

    /**
     * 初始化 Redis 连接池,并监听 Nacos 上的配置变化
     */
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        NacosConfigListener nacosConfigListener = null;
        try {
            nacosConfigListener = new NacosConfigListener(nacosServerAddr, nacosNamespace, nacosUsername, nacosPassword,
                    nacosConfigPrefix, GROUP_ID, REDIS_CONFIG_DATA_ID, REDIS_SENTINEL_CONFIG_DATA_ID,
                    REDIS_CLUSTER_CONFIG_DATA_ID);
            nacosConfigListener.init();

            String config = nacosConfigListener.getConfig(REDIS_CONFIG_DATA_ID);
            RedisConfig redisConfig = OBJECT_MAPPER.readValue(config, RedisConfig.class);
            RedisSentinelConfig redisSentinelConfig = null;
            RedisClusterConfig redisClusterConfig = null;
            if (redisConfig.isSentinel()) {
                String sentinelConfig = nacosConfigListener.getConfig(REDIS_SENTINEL_CONFIG_DATA_ID);
                redisSentinelConfig = OBJECT_MAPPER.readValue(sentinelConfig, RedisSentinelConfig.class);
            } else if (redisConfig.isCluster()) {
                String clusterConfig = nacosConfigListener.getConfig(REDIS_CLUSTER_CONFIG_DATA_ID);
                redisClusterConfig = OBJECT_MAPPER.readValue(clusterConfig, RedisClusterConfig.class);
            }
            redisConnectionFactory = createRedisConnectionFactory(redisConfig, redisSentinelConfig, redisClusterConfig);

            // 注册配置变化监听器
            nacosConfigListener.addListener(REDIS_CONFIG_DATA_ID, new ConfigChangeListener() {
                @Override
                public void receiveConfigInfo(String configInfo) {
                    LOGGER.info("redis config changed: {}", configInfo);
                    try {
                        RedisConfig newRedisConfig = OBJECT_MAPPER.readValue(configInfo, RedisConfig.class);
                        RedisSentinelConfig newRedisSentinelConfig = null;
                        RedisClusterConfig newRedisClusterConfig = null;
                        if (newRedisConfig.isSentinel()) {
                            String sentinelConfigInfo = nacosConfigListener.getConfig(REDIS_SENTINEL_CONFIG_DATA_ID);
                            newRedisSentinelConfig = OBJECT_MAPPER.readValue(sentinelConfigInfo, RedisSentinelConfig.class);
                        } else if (newRedisConfig.isCluster()) {
                            String clusterConfigInfo = nacosConfigListener.getConfig(REDIS_CLUSTER_CONFIG_DATA_ID);
                            newRedisClusterConfig = OBJECT_MAPPER.readValue(clusterConfigInfo, RedisClusterConfig.class);
                        }
                        RedisConnectionFactory newRedisConnectionFactory = createRedisConnectionFactory(newRedisConfig, newRedisSentinelConfig, newRedisClusterConfig);
                        redisConnectionFactory = newRedisConnectionFactory;
                    } catch (JsonProcessingException e) {
                        LOGGER.error("failed to parse redis config", e);
                    }
                }
            });
            if (redisConfig.isSentinel()) {
                nacosConfigListener.addListener(REDIS_SENTINEL_CONFIG_DATA_ID, new ConfigChangeListener() {
                    @Override
                    public void receiveConfigInfo(String configInfo) {
                        LOGGER.info("redis sentinel config changed: {}", configInfo);
                        try {
                            RedisSentinelConfig newRedisSentinelConfig = OBJECT_MAPPER.readValue(configInfo, RedisSentinelConfig.class);
                            RedisConnectionFactory newRedisConnectionFactory = createRedisConnectionFactory(redisConfig, newRedisSentinelConfig, null);
                            redisConnectionFactory = newRedisConnectionFactory;
                        } catch (JsonProcessingException e) {
                            LOGGER.error("failed to parse redis sentinel config", e);
                        }
                    }
                });
            } else if (redisConfig.isCluster()) {
                nacosConfigListener.addListener(REDIS_CLUSTER_CONFIG_DATA_ID, new ConfigChangeListener() {
                    @Override
                    public void receiveConfigInfo(String configInfo) {
                        LOGGER.info("redis cluster config changed: {}", configInfo);
                        try {
                            RedisClusterConfig newRedisClusterConfig = OBJECT_MAPPER.readValue(configInfo, RedisClusterConfig.class);
                            RedisConnectionFactory newRedisConnectionFactory = createRedisConnectionFactory(redisConfig, null, newRedisClusterConfig);
                            redisConnectionFactory = newRedisConnectionFactory;
                        } catch (JsonProcessingException e) {
                            LOGGER.error("failed to parse redis cluster config", e);
                        }
                    }
                });
            }
        } catch (Exception e) {
            LOGGER.error("failed to init nacos config listener", e);
        }
        return redisConnectionFactory;
    }

    // 创建 Redis 连接工厂
    private RedisConnectionFactory createRedisConnectionFactory(RedisConfig redisConfig,
                                                                RedisSentinelConfig redisSentinelConfig,
                                                                RedisClusterConfig redisClusterConfig) {
        if (redisConfig.isSentinel()) {
            RedisSentinelConfiguration sentinelConfiguration = new RedisSentinelConfiguration();
            sentinelConfiguration.setSentinelPassword(redisSentinelConfig.getSentinelPassword());
            sentinelConfiguration.setMaster(redisSentinelConfig.getMaster());
            sentinelConfiguration.setSentinel(redisSentinelConfig.getSentinels());
            sentinelConfiguration.setDatabase(redisConfig.getDatabase());
            sentinelConfiguration.setPassword(redisConfig.getPassword());

            JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(sentinelConfiguration);
            jedisConnectionFactory.getPoolConfig().setMaxIdle(redisConfig.getMaxIdle());
            jedisConnectionFactory.getPoolConfig().setMaxTotal(redisConfig.getMaxTotal());
            jedisConnectionFactory.getPoolConfig().setMinIdle(redisConfig.getMinIdle());
            jedisConnectionFactory.setHostName(redisConfig.getHostname());
            jedisConnectionFactory.setPort(redisConfig.getPort());
            jedisConnectionFactory.setTimeout(redisConfig.getTimeout());
            jedisConnectionFactory.setUsePool(true);
            return jedisConnectionFactory;
        } else if (redisConfig.isCluster()) {
            RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration(redisClusterConfig.getNodes());
            clusterConfiguration.setMaxRedirects(redisClusterConfig.getMaxRedirects());
            clusterConfiguration.setClusterPassword(redisConfig.getPassword());

            JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(clusterConfiguration);
            jedisConnectionFactory.getPoolConfig().setMaxIdle(redisConfig.getMaxIdle());
            jedisConnectionFactory.getPoolConfig().setMaxTotal(redisConfig.getMaxTotal());
            jedisConnectionFactory.getPoolConfig().setMinIdle(redisConfig.getMinIdle());
            jedisConnectionFactory.setHostName(redisConfig.getHostname());
            jedisConnectionFactory.setPort(redisConfig.getPort());
            jedisConnectionFactory.setTimeout(redisConfig.getTimeout());
            jedisConnectionFactory.setUsePool(true);
            return jedisConnectionFactory;
        } else {
            RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration();
            standaloneConfiguration.setHostName(redisConfig.getHostname());
            standaloneConfiguration.setPort(redisConfig.getPort());
            standaloneConfiguration.setDatabase(redisConfig.getDatabase());
            standaloneConfiguration.setPassword(redisConfig.getPassword());

            JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(standaloneConfiguration);
            jedisConnectionFactory.getPoolConfig().setMaxIdle(redisConfig.getMaxIdle());
            jedisConnectionFactory.getPoolConfig().setMaxTotal(redisConfig.getMaxTotal());
            jedisConnectionFactory.getPoolConfig().setMinIdle(redisConfig.getMinIdle());
            jedisConnectionFactory.setTimeout(redisConfig.getTimeout());
            jedisConnectionFactory.setUsePool(true);
            return jedisConnectionFactory;
        }
    }

    // 配置 RedisTemplate
    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }

    // 配置 RedissonClient
    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        if (redisConnectionFactory instanceof JedisConnectionFactory) {
            JedisConnectionFactory jedisConnectionFactory = (JedisConnectionFactory) redisConnectionFactory;
            String sentinels = jedisConnectionFactory.getSentinelConfiguration().getSentinels().stream()
                    .map(s -> s.getHost() + ":" + s.getPort())
                    .collect(Collectors.joining(","));
            config.useSentinelServers()
                    .setMasterName(jedisConnectionFactory.getSentinelConfiguration().getMaster())
                    .setDatabase(jedisConnectionFactory.getDatabase())
                    .setPassword(jedisConnectionFactory.getPassword())
                    .addSentinelAddress(sentinels.split(","));
        } else if (redisConnectionFactory instanceof RedisClusterConnection) {
            RedisClusterConnection redisClusterConnection = (RedisClusterConnection) redisConnectionFactory;
            String nodes = redisClusterConnection
                    .clusterGetNodes()
                    .stream()
                    .map(RedisClusterNode::getUriAsString)
                    .collect(Collectors.joining(","));
            config.useClusterServers()
                    .setMasterConnectionPoolSize(10)
                    .setSlaveConnectionPoolSize(10)
                    .addNodeAddress(nodes.split(","));
        } else {
            RedisStandaloneConfiguration standaloneConfiguration = (RedisStandaloneConfiguration) redisConnectionFactory
                    .getConnectionConfig();
            config.useSingleServer()
                    .setAddress("redis://" + standaloneConfiguration.getHostName() + ":" + standaloneConfiguration.getPort())
                    .setDatabase(standaloneConfiguration.getDatabase())
                    .setPassword(standaloneConfiguration.getPassword());
        }
        return Redisson.create(config);
    }

    // 配置 RedissonReactiveClient
    @Bean
    public RedissonReactiveClient redissonReactiveClient() {
        Config config = new Config();
        if (redisConnectionFactory instanceof JedisConnectionFactory) {
            JedisConnectionFactory jedisConnectionFactory = (JedisConnectionFactory) redisConnectionFactory;
            String sentinels = jedisConnectionFactory.getSentinelConfiguration().getSentinels().stream()
                    .map(s -> s.getHost() + ":" + s.getPort())
                    .collect(Collectors.joining(","));
            config.useSentinelServers()
                    .setMasterName(jedisConnectionFactory.getSentinelConfiguration().getMaster())
                    .setDatabase(jedisConnectionFactory.getDatabase())
                    .setPassword(jedisConnectionFactory.getPassword())
                    .addSentinelAddress(sentinels.split(","));
        } else if (redisConnectionFactory instanceof RedisClusterConnection) {
            RedisClusterConnection redisClusterConnection = (RedisClusterConnection) redisConnectionFactory;
            String nodes = redisClusterConnection
                    .clusterGetNodes()
                    .stream()
                    .map(RedisClusterNode::getUriAsString)
                    .collect(Collectors.joining(","));
            config.useClusterServers()
                    .setMasterConnectionPoolSize(10)
                    .setSlaveConnectionPoolSize(10)
                    .addNodeAddress(nodes.split(","));
        } else {
            RedisStandaloneConfiguration standaloneConfiguration = (RedisStandaloneConfiguration) redisConnectionFactory
                    .getConnectionConfig();
            config.useSingleServer()
                    .setAddress("redis://" + standaloneConfiguration.getHostName() + ":" + standaloneConfiguration.getPort())
                    .setDatabase(standaloneConfiguration.getDatabase())
                    .setPassword(standaloneConfiguration.getPassword());
        }
        return Redisson.createReactive(config);
    }

    // 配置 RedissonRxClient
    @Bean
    public RedissonRxClient redissonRxClient() {
        Config config = new Config();
        if (redisConnectionFactory instanceof JedisConnectionFactory) {
            JedisConnectionFactory jedisConnectionFactory = (JedisConnectionFactory) redisConnectionFactory;
            String sentinels = jedisConnectionFactory.getSentinelConfiguration().getSentinels().stream()
                    .map(s -> s.getHost() + ":" + s.getPort())
                    .collect(Collectors.joining(","));
            config.useSentinelServers()
                    .setMasterName(jedisConnectionFactory.getSentinelConfiguration().getMaster())
                    .setDatabase(jedisConnectionFactory.getDatabase())
                    .setPassword(jedisConnectionFactory.getPassword())
                    .addSentinelAddress(sentinels.split(","));
        } else if (redisConnectionFactory instanceof RedisClusterConnection) {
            RedisClusterConnection redisClusterConnection = (RedisClusterConnection) redisConnectionFactory;
            String nodes = redisClusterConnection
                    .clusterGetNodes()
                    .stream()
                    .map(RedisClusterNode::getUriAsString)
                    .collect(Collectors.joining(","));
            config.useClusterServers()
                    .setMasterConnectionPoolSize(10)
                    .setSlaveConnectionPoolSize(10)
                    .addNodeAddress(nodes.split(","));
        } else {
            RedisStandaloneConfiguration standaloneConfiguration = (RedisStandaloneConfiguration) redisConnectionFactory
                    .getConnectionConfig();
            config.useSingleServer()
                    .setAddress("redis://" + standaloneConfiguration.getHostName() + ":" + standaloneConfiguration.getPort())
                    .setDatabase(standaloneConfiguration.getDatabase())
                    .setPassword(standaloneConfiguration.getPassword());
        }
        return Redisson.createRx(config);
    }
}

分析一下

上面的代码中,我们实现了以下功能:

  1. 通过 Nacos 配置中心获取 Redis 连接池的配置信息,包括 Redis 的连接方式(standalone、sentinel、cluster)、节点地址、密码、数据库等。
  2. 根据配置信息创建对应的 Redis 连接池,包括 JedisConnectionFactory 和 Redisson 的连接工厂,使用 RedisTemplate、RedissonClient、RedissonReactiveClient 和 RedissonRxClient 进行 Redis 的访问。
  3. 监听 Nacos 配置变化,当 Redis 配置信息发生变化时重新初始化连接池。

此外,我们还需要实现 NacosConfigListener 来监听 Nacos 上的配置变化,以下是一个简单的实现:

public class NacosConfigListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(NacosConfigListener.class);

    private ConfigService configService;
    private String prefix;
    private String groupId;
    private String redisConfigDataId;
    private String redisSentinelConfigDataId;
    private String redisClusterConfigDataId;
    private Map<String, ConfigChangeListener> listeners = new ConcurrentHashMap<>();

    public NacosConfigListener(String serverAddr, String namespace, String username, String password, String prefix, String groupId, String redisConfigDataId, String redisSentinelConfigDataId, String redisClusterConfigDataId) throws NacosException {
        this.prefix = prefix;
        this.groupId = groupId;
        this.redisConfigDataId = redisConfigDataId;
        this.redisSentinelConfigDataId = redisSentinelConfigDataId;
        this.redisClusterConfigDataId = redisClusterConfigDataId;

        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
        properties.put(PropertyKeyConst.NAMESPACE, namespace);
        if (StringUtils.isNotBlank(username)) {
            properties.put(PropertyKeyConst.USERNAME, username);
        }
        if (StringUtils.isNotBlank(password)) {
            properties.put(PropertyKeyConst.PASSWORD, password);
        }

        configService = NacosFactory.createConfigService(properties);
    }

    public void init() throws NacosException {
        configService.addListener(prefix + redisConfigDataId, groupId, new ConfigListener() {
            @Override
            public void receiveConfigInfo(String configInfo) {
                LOGGER.info("redis config received: {}", configInfo);
                if (listeners.containsKey(redisConfigDataId)) {
                    listeners.get(redisConfigDataId).receiveConfigInfo(configInfo);
                }
            }

            @Override
            public Executor getExecutor() {
                return null;
            }
        });

        configService.addListener(prefix + redisSentinelConfigDataId, groupId, new ConfigListener() {
            @Override
            public void receiveConfigInfo(String configInfo) {
                LOGGER.info("redis sentinel config received: {}", configInfo);
                if (listeners.containsKey(redisSentinelConfigDataId)) {
                    listeners.get(redisSentinelConfigDataId).receiveConfigInfo(configInfo);
                }
            }

            @Override
            public Executor getExecutor() {
                return null;
            }
        });

        configService.addListener(prefix + redisClusterConfigDataId, groupId, new ConfigListener() {
            @Override
            public void receiveConfigInfo(String configInfo) {
                LOGGER.info("redis cluster config received: {}", configInfo);
                if (listeners.containsKey(redisClusterConfigDataId)) {
                    listeners.get(redisClusterConfigDataId).receiveConfigInfo(configInfo);
                }
            }

            @Override
            public Executor getExecutor() {
                return null;
            }
        });
    }

    public String getConfig(String dataId) throws NacosException {
        return configService.getConfig(prefix + dataId, groupId, 5000);
    }

    public void addListener(String dataId, ConfigChangeListener listener) {
        listeners.put(dataId, listener);
    }

    public void removeListener(String dataId) {
        listeners.remove(dataId);
    }
}

总结一下

我们可以在应用启动时初始化 NacosConfigListener 并通过 addListener 方法注册配置变化监听器,当配置变化时调用 listener 的 receiveConfigInfo 方法即可完成重新初始化的逻辑。需要注意的是,这里的 ConfigChangeListener 是一个接口,需要在应用中实现 receiveConfigInfo 方法,具体实现视应用而定。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot 中,可以通过 `@Value` 注解来获取 Nacos 配置中心的配置,同时也可以通过 `@NacosPropertySource` 注解来指定 Nacos 配置中心的配置源。但是,如果需要实时监听 Nacos 配置文件的变化,可以使用 Nacos 提供的监听器来实现。 具体步骤如下: 1. 在 `pom.xml` 文件中添加 Nacos 配置中心的依赖: ```xml <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> ``` 2. 在 `application.properties` 或 `application.yml` 文件中添加 Nacos 配置中心的配置: ```yml spring.cloud.nacos.config.server-addr=127.0.0.1:8848 spring.cloud.nacos.config.namespace=your_namespace spring.cloud.nacos.config.group=your_group spring.cloud.nacos.config.file-extension=properties spring.cloud.nacos.config.shared-dataids=demo.properties ``` 3. 创建一个配置类,使用 `@NacosPropertySource` 注解指定 Nacos 配置中心的配置源: ```java @Configuration @NacosPropertySource(dataId = "demo.properties", autoRefreshed = true) public class NacosConfig { @Value("${demo.config}") private String config; @PostConstruct public void init() { System.out.println(config); } } ``` 4. 在启动类上添加 `@EnableDiscoveryClient` 注解,以启用 Nacos 服务注册与发现功能。 ```java @SpringBootApplication @EnableDiscoveryClient public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 通过上述步骤,就可以实现 Spring Boot 监听 Nacos 配置文件的变化了。当 Nacos 配置中心的配置文件发生变化时,应用程序会自动更新配置,并且调用 `@Value` 注解绑定的字段也会更新。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值