nacos–基础–3.4–集成–spring–spring上下文中的一些关键的特性
1、spring上下文中的一些关键的特性
- 注解驱动
- 依赖注入
- 外部化配置
- 事件驱动
2、注解驱动
2.1、 启用 Nacos
- @EnableNacos 是一个模块驱动的注解
- @EnableNacos 支持 Nacos Spring 的所有功能
- 服务发现:等于 @EnableNacosDiscovery
- 配置管理:等于 @EnableNacosConfig
- 它等于 @EnableNacosDiscovery 加上 @EnableNacosConfig,可以单独配置并在不同场景中使用。
2.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 支持更丰富的类型转换。
2.2.1、 类型
- @NacosConfigListener 的类型转换有2类
- 内置类型转换
- 自定义类型转换
- 默认情况:内置类型转换 基于 Spring DefaultFormattingConversionService,这意味着它包含了大多数情况以及 Spring 框架更高级版本的丰富功能。
2.2.1.1、举例
前面示例中的内容 “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
}
2.2.1.2、nacos-spring-context 为开发人员提供弹性扩展
- 如果定义名为nacosConfigConversionService的Spring Bean,其类型为ConversionService,则将忽略DefaultFormattingConversionService。
- 可以自定义NacosConfigConverter接口的实现,以指定类型转换的侦听器方法
2.2.1.3、可以自定义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());
}
2.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 超过50毫秒,就抛异常,也就是说integerValue不会被赋值
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
}
2.3、 全局和自定义 Nacos 属性
- globalProperties 是任何 @EnableNacos,@EnableNacosDiscovery 或 @EnableNacosConfig 中的必选属性
- globalProperties 类型为 @NacosProperties。
- globalProperties 将初始化为其他注解或组件的 “全局 Nacos 属性”
- 例如:@NacosInjected。
- globalProperties 定义全局和默认属性
- 具有最低优先级
- 可以被覆盖
2.3.1、 覆盖优先级
- 自定义的 Nacos 属性
- 由 @NacosProperties 配置。
- 是可选的
- 用于在特殊情况下覆盖全局 Nacos 属性。
- 非自定义的 Nacos 属性
- Nacos 属性将尝试从 @EnableNacosConfig.globalProperties() 或 @EnableNacosDiscovery.globalProperties() 或 @EnableNacos.globalProperties() 中查找属性。
2.4、 @NacosProperties
- @NacosProperties 是全局和自定义 Nacos 属性的统一注解。
- @NacosProperties 充当Java Properties 和 NacosFactory 类之间的中介。
- NacosFactory 负责创建 ConfigService 或 NamingService 实例。
2.4.1、 占位符
- @NacosProperties 的属性完全支持占位符,它的源是Spring Environment 抽象中的各种 PropertySource,通常是Java System Properties 和操作系统环境变量。
- 所有占位符的前缀都是 nacos.
2.4.2、@NacosProperties 和 Nacos 属性的属性之间的映射
注意:@EnableNacosDiscovery 和 @EnableNacosConfig 之间 globalProperties() 的占位符存在一些差异:
- 这些 @EnableNacosDiscovery 和 @EnableNacosConfig 的占位符用于隔离不同的 Nacos 服务,在大多数情况下都是不必要的。
- 默认情况下,将使用常规占位符。
3、 依赖注入(@NacosInjected)
- @NacosInjected 用于在Spring Beans 中注入 ConfigService 或 NamingService 实例,并使这些实例可缓存。
- 如果它们的 @NacosProperties 相等,则实例将是相同的,无论属性是来自全局还是自定义的 Nacos 属性
3.1、案例
@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 实例是相同的。 namingService 和 namingService2 也是如此。
3.2、注意
与 NacosFactory.createConfigService() 方法创建的 ConfigService 实例不同,@NacosInjected 注解创建的 ConfigService 实例支持 Nacos Spring 事件。 例如,在增强的 ConfigService 调用 publishConfig() 方法之后会有一个 NacosConfigPublishedEvent。
4、外部化配置
- 外部化配置是 Spring Boot 引入的概念,它允许应用程序接收外部属性源以控制运行时行为。
- Nacos Server 在应用程序外部运行单独的进程以维护应用程序配置。
- nacos-spring-context 提供了对象绑定,动态配置(自动刷新)等功能。
4.1、nacos-spring-context 和 Spring Stack 之间的简单比较
5、 事件驱动
- Nacos 事件驱动 基于标准的 Spring Event / Listener 机制。
- Spring 的 ApplicationEvent 是所有 Nacos Spring 事件的抽象超类