返回介绍

Nacos Spring

发布于 2021-03-27 16:56:00 字数 16185 浏览 1176 评论 0 收藏 0

本文将介绍 nacos-spring-context 中的一些关键的特性:

  • 注解驱动
  • 依赖注入
  • 外部化配置
  • 事件驱动

1. 注解驱动

1.1. 启用 Nacos

@EnableNacos是一个模块驱动的注解,它支持 Nacos Spring 的所有功能,包括服务发现配置管理。它等于 @EnableNacosDiscovery 加上 @EnableNacosConfig,可以单独配置并在不同场景中使用。

1.2. 配置监听

假设在 Nacos 服务中有一个配置,其 dataId 是 "testDataId" 而 groupId 是默认组("DEFAULT_GROUP")。 现在,您可以使用 ConfigService#publishConfig 方法更改其内容:

@NacosInjected
private ConfigService configService;

@Test
public void testPublishConfig() throws NacosException {
    configService.publishConfig(DATA_ID, DEFAULT_GROUP, "9527");
}

然后您可以添加一个监听器,它将监听配置的变化。 您可以通过在 Spring Bean 中添加配置变更监听器方法来执行此操作:

@NacosConfigListener(dataId = DATA_ID)
public void onMessage(String config) {
    assertEquals("mercyblitz", config); // asserts true
}

下面的代码具有相同的效果:

configService.addListener(DATA_ID, DEFAULT_GROUP, new AbstractListener() {
    @Override
    public void receiveConfigInfo(String config) {
        assertEquals("9527", config); // asserts true
    }
});

另外,@NacosConfigListener 支持更丰富的类型转换。

1.2.1. 类型

@NacosConfigListener 的类型转换包括内置和自定义实现。 默认情况下,内置类型转换基于 Spring DefaultFormattingConversionService,这意味着它包好了大多数情况以及 Spring 框架更高级版本的丰富功能。

例如,前面示例中的内容 "9527" 也可以通过带 "int" 或 "Integer" 参数的方法进行监听::

@NacosConfigListener(dataId = DATA_ID)
public void onInteger(Integer value) {
    assertEquals(Integer.valueOf(9527), value); // asserts true
}

@NacosConfigListener(dataId = DATA_ID)
public void onInt(int value) {
    assertEquals(9527, value); // asserts true
}

当然, nacos-spring-context 为开发人员提供弹性扩展。 如果定义名为nacosConfigConversionService的Spring Bean,其类型为ConversionService,则将忽略DefaultFormattingConversionService。 此外,您可以自定义NacosConfigConverter接口的实现,以指定类型转换的侦听器方法:

public class UserNacosConfigConverter implements NacosConfigConverter<User> {

    @Override
    public boolean canConvert(Class<User> targetType) {
        return true;
    }

    @Override
    public User convert(String source) {
        return JSON.parseObject(source, User.class);
    }
}

UserNacosConfigConverter 类绑定在 @NacosConfigListener.converter() 属性上,如下:

@NacosInjected
private ConfigService configService;

@Test
public void testPublishUser() throws NacosException {
    configService.publishConfig("user", DEFAULT_GROUP, "{\"id\":1,\"name\":\"mercyblitz\"}");
}

@NacosConfigListener(dataId = "user", converter = UserNacosConfigConverter.class)
public void onUser(User user) {
    assertEquals(Long.valueOf(1L), user.getId()); 
    assertEquals("mercyblitz", user.getName());
}

1.2.2. 超时时间

由于运行自定义的 NacosConfigConverter 可能需要一些时间,因此您可以在 @NacosConfigListener.timeout() 属性中设置最大执行时间,以防止它阻塞其他侦听器:

@Configuration
public class Listeners {

    private Integer integerValue;

    private Double doubleValue;

    @NacosConfigListener(dataId = DATA_ID, timeout = 50)
    public void onInteger(Integer value) throws Exception {
        Thread.sleep(100); // timeout of execution
        this.integerValue = value;
    }

    @NacosConfigListener(dataId = DATA_ID, timeout = 200)
    public void onDouble(Double value) throws Exception {
        Thread.sleep(100); // normal execution
        this.doubleValue = value;
    }

    public Integer getIntegerValue() {
        return integerValue;
    }

    public Double getDoubleValue() {
        return doubleValue;
    }
}

Listeners Bean 的 integerValue 总是为null,不会改变。 因此,以下断言都将是 true

@Autowired
private Listeners listeners;

@Test
public void testPublishConfig() throws NacosException {
    configService.publishConfig(DATA_ID, DEFAULT_GROUP, "9527");
    assertNull(listeners.getIntegerValue()); // asserts true
    assertEquals(Double.valueOf(9527), listeners.getDoubleValue());   // asserts true
}

1.3. 全局和自定义 Nacos 属性

globalProperties 是任何 @EnableNacos@EnableNacosDiscovery@EnableNacosConfig 中的必选属性,其类型为 @NacosProperties

globalProperties 将初始化为其他注解或组件的 "全局 Nacos 属性",例如:@NacosInjected

换句话说,全局 Nacos 属性 定义全局和默认属性。它设置为具有最低优先级,并且也可以被覆盖。覆盖优先级如下表所示:

Precedence OrderNacos AnnotationRequired
1*.properties()N
2@EnableNacosConfig.globalProperties() or @EnableNacosDiscovery.globalProperties()Y
3@EnableNacos.globalProperties()Y

*.properties() 定义来自以下之一的自定义 Nacos 属性:

  • @NacosInjected.properties()
  • @NacosConfigListener.properties()
  • @NacosPropertySource.properties()
  • @NacosConfigurationProperties.properties()

自定义的 Nacos 属性也由 @NacosProperties 配置。 不过,它们是可选的,用于在特殊情况下覆盖全局 Nacos 属性。 如果没有定义,Nacos 属性将尝试从 @EnableNacosConfig.globalProperties()@EnableNacosDiscovery.globalProperties()@EnableNacos.globalProperties() 中查找属性。

1.4. @NacosProperties

@NacosProperties 是全局和自定义 Nacos 属性的统一注解。 它充当Java PropertiesNacosFactory 类之间的中介。NacosFactory 负责创建 ConfigServiceNamingService 实例。

@NacosProperties 的属性完全支持占位符,它的源是Spring Environment 抽象中的各种 PropertySource,通常是Java System Properties 和操作系统环境变量。 所有占位符的前缀都是 nacos.@NacosProperties 和 Nacos 属性的属性之间的映射如下所示:

AttributePropertyPlaceholderDescriptionRequired
endpoint()endpoint${nacos.endpoint:}N
namespace()namespace${nacos.namespace:}N
accessKey()access-key${nacos.access-key:}N
secretKey()secret-key${nacos.secret-key:}N
serverAddr()server-addr${nacos.server-addr:}Y
contextPath()context-path${nacos.context-path:}N
clusterName()cluster-name${nacos.cluster-name:}N
encode()encode${nacos.encode:UTF-8}N

请注意,@EnableNacosDiscovery@EnableNacosConfig 之间 globalProperties() 的占位符存在一些差异:

Attribute@EnableNacosDiscovery's Placeholder@EnableNacosConfig's Placeholder
endpoint()${nacos.discovery.endpoint:${nacos.endpoint:}}${nacos.config.endpoint:${nacos.endpoint:}}
namespace()${nacos.discovery.namespace:${nacos.namespace:}}${nacos.config.namespace:${nacos.namespace:}}
accessKey()${nacos.discovery.access-key:${nacos.access-key:}}${nacos.config.access-key:${nacos.access-key:}}
secretKey()${nacos.discovery.secret-key:${nacos.secret-key:}}${nacos.config.secret-key:${nacos.secret-key:}}
serverAddr()${nacos.discovery.server-addr:${nacos.server-addr:}}${nacos.config.server-addr:${nacos.server-addr:}}
contextPath()${nacos.discovery.context-path:${nacos.context-path:}}${nacos.config.context-path:${nacos.context-path:}}
clusterName()${nacos.discovery.cluster-name:${nacos.cluster-name:}}${nacos.config.cluster-name:${nacos.cluster-name:}}
encode()${nacos.discovery.encode:${nacos.encode:UTF-8}}${nacos.config.encode:${nacos.encode:UTF-8}}

这些 @EnableNacosDiscovery@EnableNacosConfig 的占位符用于隔离不同的 Nacos 服务,在大多数情况下都是不必要的。默认情况下,将使用常规占位符。

2. 依赖注入

@NacosInjected 是一个核心注解,用于在Spring Beans 中注入 ConfigServiceNamingService 实例,并使这些实例可缓存。 这意味着如果它们的 @NacosProperties 相等,则实例将是相同的,无论属性是来自全局还是自定义的 Nacos 属性:

@NacosInjected
private ConfigService configService;

@NacosInjected(properties = @NacosProperties(encode = "UTF-8"))
private ConfigService configService2;

@NacosInjected(properties = @NacosProperties(encode = "GBK"))
private ConfigService configService3;

@NacosInjected
private NamingService namingService;

@NacosInjected(properties = @NacosProperties(encode = "UTF-8"))
private NamingService namingService2;

@NacosInjected(properties = @NacosProperties(encode = "GBK"))
private NamingService namingService3;

@Test
public void testInjection() {

    Assert.assertEquals(configService, configService2);
    Assert.assertNotEquals(configService2, configService3);

    Assert.assertEquals(namingService, namingService2);
    Assert.assertNotEquals(namingService2, namingService3);
}

属性 configService 使用 @EnableNacos#globalProperties()@EnableNacosConfig#globalProperties(),因为 encode 属性的默认值是 "UTF-8",因此 configService 实例和由 @NacosProperties(encode ="UTF-8") 注解的 configService2 实例是相同的。 namingServicenamingService2 也是如此。

值得注意的是,与 NacosFactory.createConfigService() 方法创建的 ConfigService 实例不同,@NacosInjected 注解创建的 ConfigService 实例支持 Nacos Spring 事件。 例如,在增强的 ConfigService 调用 publishConfig() 方法之后会有一个 NacosConfigPublishedEvent。 有关更多详细信息,请参阅"事件驱动"部分。

3. 外部化配置

外部化配置是 Spring Boot 引入的概念,它允许应用程序接收外部属性源以控制运行时行为。 Nacos Server 在应用程序外部运行单独的进程以维护应用程序配置。 nacos-spring-context 提供了对象绑定,动态配置(自动刷新)等功能。

这里有 nacos-spring-context 和 Spring Stack 之间的简单比较:

Spring StackNacos SpringHighlight
@Value@NacosValueauto-refreshed
@ConfigurationProperties@NacosConfigurationPropertiesauto-refreshed,@NacosProperty,@NacosIgnore
@PropertySource@NacosPropertySourceauto-refreshed, precedence order control
@PropertySources@NacosPropertySources

4. 事件驱动

Nacos 事件驱动 基于标准的 Spring Event / Listener 机制。 Spring 的 ApplicationEvent 是所有 Nacos Spring 事件的抽象超类:

Nacos Spring EventTrigger
NacosConfigPublishedEventAfter ConfigService.publishConfig()
NacosConfigReceivedEventAfterListener.receiveConfigInfo()
NacosConfigRemovedEventAfter configService.removeConfig()
NacosConfigTimeoutEventConfigService.getConfig() on timeout
NacosConfigListenerRegisteredEventAfter ConfigService.addListner() or ConfigService.removeListener()
NacosConfigurationPropertiesBeanBoundEventAfter @NacosConfigurationProperties binding
NacosConfigMetadataEventAfter Nacos Config operations

相关项目

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文