Heycm

Heycm

包装Naocs配置监听/推送并在Spring中的应用

2023-11-10
包装Naocs配置监听/推送并在Spring中的应用

前言

Nacos SKD 已经提供了多种方式监听配置变更,但是我用着还不是很舒服,所以就产生了这个包装,主要也是为了更方便使用吧。

说起来也就是包装了 Nacos SDK 的两个接口而已

// 监听
NacosConfigService.addListener(String dataId, String group, Listener listener)
// 推送
NacosConfigService.publishConfig(String dataId, String group, String content)

在引入依赖自动装配,实现开箱即用,除此之外没有别的了。

包装思路

配置类

先定义一个配置类,读Nacos连接参数,用于初始化NacosConfigService实例

/**
 * Nacos配置参数
 *
 * @author heycm
 * @since 2023/11/8 19:15
 */
@ConfigurationProperties(prefix = "spring.cloud.nacos.config")
public class NacosProperties {

    private String serverAddr;

    private String namespace;

    private String username;

    private String password;

    private String group = "DEFAULT_GROUP";
    
    // 省略 getter setter
}

监听器

如代码

/**
 * Nacos配置更新监听处理者,在业务代码中实现,处理监听到推送变更后的逻辑
 *
 * @author heycm
 * @since 2023/11/8 19:19
 */
@FunctionalInterface
public interface NacosConfReceiver {

    void receiveConf(String config);

}


/**
 * Nacos配置监听器
 *
 * @author heycm
 * @since 2023/11/8 19:19
 */
public interface NacosConfListener {

    void addListener(String dataId, NacosConfReceiver receiver);

    void addListener(String dataId, String group, NacosConfReceiver receiver);
}


/**
 * Nacos配置监听器实现
 *
 * @author heycm
 * @since 2023/11/8 19:25
 */
@Slf4j
public class NacosConfListenerImpl implements NacosConfListener {

    private final NacosProperties nacosProperties;

    private final ConfigService configService;

    public NacosConfListenerImpl(NacosProperties nacosProperties, ConfigService configService) {
        this.nacosProperties = nacosProperties;
        this.configService = configService;
        log.info("Nacos监听器注册配置: {}", nacosProperties);
        log.info("Nacos监听器注册: {}", configService);
    }

    @Override
    public void addListener(String dataId, NacosConfReceiver receiver) {
        addListener(dataId, nacosProperties.getGroup(), receiver);
    }

    @Override
    public void addListener(String dataId, String group, NacosConfReceiver receiver) {
        log.info("注册[dataId: {}, group: {}]配置监听", dataId, group);
        try {
            String config = configService.getConfigAndSignListener(dataId, group, 3000L, new AbstractListener() {
                @Override
                public void receiveConfigInfo(String config) {
                    log.info("收到[dataId: {}, group: {}]配置更新: {}", dataId, group, config);
                    receiver.receiveConf(config);
                }
            });
            // boot init receive
            receiver.receiveConf(config);
        } catch (NacosException e) {
            log.info("注册监听器发生异常", e);
        }
    }
}

推送器

如代码

/**
 * Nacos配置推送器
 *
 * @author heycm
 * @since 2023/11/8 19:20
 */
public interface NacosConfPublisher {

    boolean publish(String dataId, String content);

    boolean publish(String dataId, String group, String content);
}


/**
 * Nacos配置推送器
 *
 * @author heycm
 * @since 2023/11/8 19:21
 */
@Slf4j
public class NacosConfPublisherImpl implements NacosConfPublisher {

    private final NacosProperties nacosProperties;

    private final ConfigService configService;

    public NacosConfPublisherImpl(NacosProperties nacosProperties, ConfigService configService) {
        this.nacosProperties = nacosProperties;
        this.configService = configService;
        log.info("Nacos推送器注册配置: {}", nacosProperties);
        log.info("Nacos推送器注册: {}", configService);
    }

    @Override
    public boolean publish(String dataId, String content) {
        return publish(dataId, nacosProperties.getGroup(), content);
    }

    @Override
    public boolean publish(String dataId, String group, String content) {
        try {
            log.info("推送[dataId: {}, group: {}]配置更新: {}", dataId, group, content);
            return configService.publishConfig(dataId, group, content);
        } catch (NacosException e) {
            log.error("推送配置发生异常", e);
        }
        return false;
    }
}

配置类

spring.factories文件中配置此类,在引入此包时自动注册,从而激活此的能力

/**
 * 配置监听/推送自动装配
 *
 * @author heycm
 * @since 2023/11/8 19:17
 */
@Configuration
@EnableConfigurationProperties({NacosProperties.class, BaseNacosConf.class})
public class NacosAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean(value = {ConfigService.class})
    public ConfigService configService(NacosProperties nacosProperties) throws NacosException {
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, nacosProperties.getServerAddr());
        properties.put(PropertyKeyConst.NAMESPACE, nacosProperties.getNamespace());
        if (!StringUtils.isEmpty(nacosProperties.getUsername()) && !StringUtils.isEmpty(nacosProperties.getPassword())) {
            properties.put(PropertyKeyConst.USERNAME, nacosProperties.getUsername());
            properties.put(PropertyKeyConst.PASSWORD, nacosProperties.getPassword());
        }
        return NacosFactory.createConfigService(properties);
    }

    @Bean
    @ConditionalOnMissingBean(value = {NacosConfListener.class})
    public NacosConfListener nacosConfListener(NacosProperties nacosProperties, ConfigService configService) {
        return new NacosConfListenerImpl(nacosProperties, configService);
    }

    @Bean
    @ConditionalOnMissingBean(value = {NacosConfPublisher.class})
    public NacosConfPublisher nacosConfPublisher(NacosProperties nacosProperties, ConfigService configService) {
        return new NacosConfPublisherImpl(nacosProperties, configService);
    }

}

使用

需要maven打包到本地仓库,进入项目目录

D:\code\online-heycm-platform> mvn install -Dmaven.test.skip=true

在项目中引入

<dependency>
  <groupId>online.heycm.platform</groupId>
  <artifactId>online-heycm-platform-nacos</artifactId>
  <version>1.0</version>
</dependency>

配置文件,配置参数按实际修改

spring:
  application:
    name: app-nacosconf
  profiles:
    active: prod
  cloud:
    nacos:
      config:
        server-addr: 192.168.2.12:8848
        namespace: nacos-conf
        file-extension: yaml
      discovery:
        server-addr: ${spring.cloud.nacos.config.server-addr}
        namespace: ${spring.cloud.nacos.config.namespace}

启动类扫描一下此包 online.heycmcom.xxx 是你项目的基础包路径

@SpringBootApplication
@ComponentScan(basePackages = {"com.xxx", "online.heycm"})
public class Application {

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

}

在需要的地方(一般是配置类)注入监听器和推送器实例使用就行

@Autowired
private NacosConfListener nacosConfListener;
@Autowired
private NacosConfPublisher nacosConfPublisher;

nacosConfListener.addListener("read", config -> {
    // 配置文件read更新后的内容 config
});

nacosConfPublisher.publish("write", "推送到配置文件write的内容");