首次搭建一个使用nacos的项目:
- https://cloud.tencent.com/developer/article/1881617
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration,\
com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,\
com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration,\
com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\
com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration,\
com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration,\
com.alibaba.cloud.nacos.NacosServiceAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration
nacos-client端底层的核心类是HostReactor
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@ConditionalOnProperty(value = "spring.cloud.nacos.discovery.enabled",matchIfMissing = true)
public @interface ConditionalOnNacosDiscoveryEnabled {
}
启用服务发现时会创建该类,这个类是包含了以spring.cloud.nacos.discovery
开头的nacos配置信息
spring cloud中定义服务发现的类是DiscoveryClient , 在nacos中实现类为NacosDiscoveryClient; 而NacosDiscoveryClient是NacosServiceDiscovery的包装类, 通过NacosServiceManager来进行实际的操作
public class NacosServiceRegistry implements ServiceRegistry<Registration> {
private final NacosDiscoveryProperties nacosDiscoveryProperties;
@Autowired
private NacosServiceManager nacosServiceManager;
//客户端往nacos注册中心进行服务注册
@Override
public void register(Registration registration) {
if (StringUtils.isEmpty(registration.getServiceId())) {
log.warn("No service to register for nacos client...");
return;
}
NamingService namingService = namingService();
String serviceId = registration.getServiceId();
String group = nacosDiscoveryProperties.getGroup();
//当前节点实例信息
Instance instance = getNacosInstanceFromRegistration(registration);
try {
//通过beanReactor创建心跳检测任务(有一定配置,默认是true,创建临时节点,定时查询nacos,如果nacos上没找到就重新注册上去)
//通过serverProxy往nacos客户端注册服务实例
namingService.registerInstance(serviceId, group, instance);
}
catch (Exception e) {
rethrowRuntimeException(e);
}
}
}
nacos服务管理,逻辑全部委派给NamingService或NamingMaintainService来操作
这个类应该是与NacosNamingService有相反的作用,
NacosNamingService是主动获取或者被动接受nacos的消息,但是不能操作,相当于crud的r
该类是可以操作nacos,拥有了crud的cud功能
NacosServiceManager管理的NamingService的实现类,一个NacosServiceManager持有的NacosNamingService是一个单例对象,创建方式是典型的懒汉模式
private NamingService buildNamingService(Properties properties) {
if (Objects.isNull(namingService)) {
synchronized (NacosServiceManager.class) {
if (Objects.isNull(namingService)) {
namingService = createNewNamingService(properties);
}
}
}
return namingService;
}
通过NamingProxy类对服务进行管理
通过BeatReactor类做心跳检测
通过HostReactor类做事件处理
命名代理, 主要作用是与nacos之间进行交互
对于nacos需要账号密码的开启定时任务;定时刷新登录nacos服务端的token
当前服务进行注册并且节点是临时节点(默认注册的就是临时节点)时, 会创建心跳检测任务,NacosServiceRegistry中有注释进行解释
任务的key=groupname+服务名称+ip+port; 如 : DEFAULT_GROUP@@nacos-consumer#172.23.215.241#8090
如果nacos的服务注册与发现有内核,这个类可能就是内核吧
public class HostReactor implements Closeable {
private static final long DEFAULT_DELAY = 1000L;
private static final long UPDATE_HOLD_INTERVAL = 5000L;
private final Map<String, ScheduledFuture<?>> futureMap = new HashMap<String, ScheduledFuture<?>>();
//服务的内存缓存
private final Map<String, ServiceInfo> serviceInfoMap;
//临时记录节点变更
private final Map<String, Object> updatingMap;
//本地启用一个udp端口,主动接受服务端的变更通知
private final PushReceiver pushReceiver;
//心跳检测 - 在这个类中创建心跳检测任务
private final BeatReactor beatReactor;
//nacos交互代理
private final NamingProxy serverProxy;
//failover-mode 模式下,使用本地文件代替内存缓存来返回服务信息
private final FailoverReactor failoverReactor;
//本地文件缓存的地址,默认 user.home\nacos\naming\namespace
private final String cacheDir;
private final boolean pushEmptyProtection;
private final ScheduledExecutorService executor;
//实例变更事件的订阅者
private final InstancesChangeNotifier notifier;
public HostReactor(NamingProxy serverProxy, BeatReactor beatReactor, String cacheDir, boolean loadCacheAtStart,
boolean pushEmptyProtection, int pollingThreadCount) {
// init executorService
this.executor = new ScheduledThreadPoolExecutor(pollingThreadCount, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName("com.alibaba.nacos.client.naming.updater");
return thread;
}
});
this.beatReactor = beatReactor;
this.serverProxy = serverProxy;
this.cacheDir = cacheDir;
if (loadCacheAtStart) {
this.serviceInfoMap = new ConcurrentHashMap<String, ServiceInfo>(DiskCache.read(this.cacheDir));
} else {
this.serviceInfoMap = new ConcurrentHashMap<String, ServiceInfo>(16);
}
this.pushEmptyProtection = pushEmptyProtection;
this.updatingMap = new ConcurrentHashMap<String, Object>();
this.failoverReactor = new FailoverReactor(this, cacheDir);
this.pushReceiver = new PushReceiver(this);
this.notifier = new InstancesChangeNotifier();
//注册一个InstancesChangeEvent事件的发布器,将notifier作为订阅者
NotifyCenter.registerToPublisher(InstancesChangeEvent.class, 16384);
NotifyCenter.registerSubscriber(notifier);
}
}
类似于zookeeper的节点信息, 节点示例:
{"name":"DEFAULT_GROUP@@nacos-consumer","clusters":"DEFAULT","cacheMillis":10000,"hosts":[{"instanceId":"172.23.215.241#8090#DEFAULT#DEFAULT_GROUP@@nacos-consumer","ip":"172.23.215.241","port":8090,"weight":1.0,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"DEFAULT","serviceName":"DEFAULT_GROUP@@nacos-consumer","metadata":{"preserved.register.source":"SPRING_CLOUD"},"instanceHeartBeatInterval":5000,"instanceHeartBeatTimeOut":15000,"ipDeleteTimeout":30000}],"lastRefTime":1632383613389,"checksum":"","allIPs":false,"reachProtectionThreshold":false,"valid":true}
这个方法在看代码的时候有一些疑惑的地方,在debug后整理如下:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。