Nacos动态配置
一、代码编写
1. yaml配置
nacos:
config:
server-addr: ***:8848
namespace: ****
accessKey: ****
secretKey: ****
2. NacosConfig
package com.hho.item.center.config;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Properties;
import java.util.concurrent.Executor;
/**
* @program: item-center
* @description:
* @author: SunYang
* @create: 2023-10-19
**/
@Component
@Slf4j
public class NacosConfig {
private static final String DATA_ID = "***-id";
private static final String GROUP = "****";
private static final long DEFAULT_TIMEOUT = 5000;
@Value("${nacos.config.server-addr}")
private String nacosServerAddr;
@Value("${nacos.config.namespace}")
private String namespace;
@Value("${nacos.accessKey}")
private String accessKey;
@Value("${nacos.secretKey}")
private String secretKey;
@PostConstruct
public void init() {
try {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, nacosServerAddr);
properties.put(PropertyKeyConst.NAMESPACE, namespace);
properties.put(PropertyKeyConst.ACCESS_KEY, accessKey);
properties.put(PropertyKeyConst.SECRET_KEY, secretKey);
// 创建ConfigService
ConfigService configService = NacosFactory.createConfigService(properties);
// 获取配置
String config = configService.getConfig(DATA_ID, GROUP, DEFAULT_TIMEOUT);
// 转化成对应的config实体
NacosJsonConfig nacosJsonConfig = NacosJsonConfig.parse(config);
// 设置congfig上下文类
NacosJsonConfigContext.set(nacosJsonConfig);
log.info("Successfully fetched and set initial configuration from Nacos.");
// 监听更新
configService.addListener(DATA_ID, GROUP, new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
NacosJsonConfig nacosJsonConfig = NacosJsonConfig.parse(configInfo);
// 刷新上下文类配置
NacosJsonConfigContext.set(nacosJsonConfig);
log.info("Received and updated configuration from Nacos.");
}
});
} catch (NacosException e) {
log.error("Failed to initialize AquamanNoticeConfiguration.", e);
throw new RuntimeException("INIT_NACOS_ERROR", e);
}
}
}
3. config实体
package com.hho.item.center.config;
import com.alibaba.fastjson.JSON;
import lombok.Data;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
/**
* @program: item-center
* @description:
* @author: SunYang
* @create: 2023-10-19
**/
@Getter
@Data
public class NacosJsonConfig {
private String itemId;
public static NacosJsonConfig parse (String config) {
// 如果config是空,则从配置上下文类中获取,避免因nacos故障导致读取不到配置
if (StringUtils.isBlank(config)) {
return NacosJsonConfigContext.get();
}
return JSON.parseObject(config, NacosJsonConfig.class);
}
}
4. NacosJsonConfigContext 上下文类
package com.hho.item.center.config;
/**
* @program: item-center
* @description: nacos配置上下文
* @author: SunYang
* @create: 2023-10-19
**/
public class NacosJsonConfigContext {
// 保证更新对其他线程立即可见
private static volatile NacosJsonConfig instance = new NacosJsonConfig();
public static void set(NacosJsonConfig nacosJsonConfig) {
instance = nacosJsonConfig;
}
public static NacosJsonConfig get() {
return instance;
}
}
二、代码解析
一、整体解析
-
NacosConfig.java
-
这是一个Spring组件,主要用于初始化与Nacos服务器的连接,并从中获取配置信息。
-
类中定义了一些静态常量如
DATA_ID
,GROUP
和DEFAULT_TIMEOUT
,它们被用于从Nacos获取配置。 -
使用
@Value
注解从Spring环境中注入了Nacos的连接参数。 -
@PostConstruct
标记的init()
方法将在bean初始化后执行,主要负责以下操作:- 构造连接Nacos所需的属性。
- 创建Nacos
ConfigService
实例。 - 使用
configService.getConfig()
方法获取初始配置。 - 将获取的配置解析为
NacosJsonConfig
对象并设置到NacosJsonConfigContext
中。 - 向Nacos注册一个监听器,用于监听配置变化。当配置发生变化时,解析新的配置并更新
NacosJsonConfigContext
。
-
-
ImQuickJumpTagConfig.java
- 提供了一个静态的
parse
方法,将JSON字符串解析为NacosJsonConfig
对象。如果提供的字符串为空,它会返回NacosJsonConfigContext
中的默认值。
- 提供了一个静态的
-
NacosJsonConfigContext.java
- 这是一个简单的上下文类,用于存储和检索当前的
NacosJsonConfig
实例。 - 它包含一个静态的
NacosJsonConfig
实例,默认为一个新的空实例。 - 提供了
set
和get
方法,分别用于更新和检索NacosJsonConfig
实例。
- 这是一个简单的上下文类,用于存储和检索当前的
总结:使用Nacos客户端API与Nacos服务器通讯,并在配置发生变化时进行更新。这个配置被保存在一个上下文中,可以在应用的其他部分进行访问和使用。
二、NacosJsonConfigContext 的意义是什么?
NacosJsonConfigContext
类在你的代码中充当了一个中央存储或"上下文"的角色,用于存储当前的 NacosJsonConfigContext
配置实例。该上下文使得其他的代码部分可以轻松访问这个配置,而不必每次都从Nacos或其他来源重新获取。
具体的意义和用途如下:
- 集中化的存储:它为
NacosJsonConfigContext
提供了一个集中的存储位置。这意味着,不管配置是从哪里来的(在你的例子中是从Nacos),只要它被解析和设置,其他的代码就可以从这个上下文中获取它。 - 简化访问:有了这个上下文,其他的代码部分不需要知道配置的来源或如何解析它。他们只需要调用
NacosJsonConfigContext.get()
就可以获取当前的配置。 - 实时更新:如果Nacos中的配置发生了变化,你的代码会自动更新存储在
NacosJsonConfigContext
中的配置实例。这确保了应用程序的其他部分总是能够访问到最新的配置,而不必重新从Nacos获取。 - 默认配置:在你的实现中,如果某些原因导致配置不能被解析(例如Nacos返回了空字符串),
NacosJsonConfigContext
会返回一个默认的配置实例,从而避免可能的空指针异常或其他错误。 - 灵活性:未来,如果你决定更改配置的来源或解析方法,只需要在相应的位置更新
NacosJsonConfigContext
,而不必更改所有使用该配置的代码部分。
总之,NacosJsonConfigContext
在你的应用程序中充当了一个中间人的角色,它连接了配置的来源(Nacos)和使用该配置的其他代码部分。这种模式提供了一个集中的存储位置,并简化了配置的访问和更新。
三、涉及的设计模式
代码涉及几个设计模式,具体如下:
- 单例模式(Singleton Pattern): 在
ImQuickJumpTagConfigContext
类中,你使用了一个静态的ImQuickJumpTagConfig
实例来表示全局的单一实例。这是单例模式的一个简化版本,确保了整个应用只有一个ImQuickJumpTagConfig
实例。虽然你的实现没有使用常见的“双重检查锁定”或“静态内部类”方法来实现线程安全的单例,但其目的与单例模式是一致的。 - 观察者模式(Observer Pattern): 你的代码中,通过 Nacos 的
configService.addListener
方法来注册一个监听器,当 Nacos 中的配置发生变化时,这个监听器会被触发,从而实时更新ImQuickJumpTagConfig
的状态。这就是观察者模式,其中 Nacos 是主题(Subject),而你注册的监听器是观察者(Observer)。 - 工厂模式(Factory Pattern): 你使用了
NacosFactory.createConfigService(properties)
来获取ConfigService
的实例。这里的NacosFactory
就是一个工厂,它根据给定的属性生成并返回相应的对象。 - 上下文模式(Context Pattern):
ImQuickJumpTagConfigContext
充当了上下文角色,它封装了特定的状态(ImQuickJumpTagConfig
实例)并为其他对象提供了统一的访问接口。虽然这不是传统的设计模式,但它在软件设计中是一种常见的做法。