Spring Cloud 2.2.2 源碼之五十四nacos服務端處理註冊實例請求二
客戶端註冊實例流程
ServiceManager的putServiceAndInit
繼續上一篇,開始進來的時候服務爲空,於是創建一個Service
,設置好屬性,然後進行初始化並放入映射和監聽器裏。我們先將臨時的服務情況,也就是關閉了就沒了。臨時的服務實例key
可能是這樣com.alibaba.nacos.naming.iplist.ephemeral.public##DEFAULT_GROUP@@cloud-alibaba-provider-payment
,永久的是com.alibaba.nacos.naming.iplist.public##DEFAULT_GROUP@@cloud-alibaba-provider-payment
,其實就是臨時的在public
前多了ephemeral
。
private void putServiceAndInit(Service service) throws NacosException {
putService(service);//添加到命名空間中
service.init();//心跳初始化
//生成key放入一致性服務裏,永久的和臨時的
consistencyService.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), true), service);
consistencyService.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), false), service);
Loggers.SRV_LOG.info("[NEW-SERVICE] {}", service.toJSON());
}
ServiceManager的putService
放進命名空間映射中。
public void putService(Service service) {
if (!serviceMap.containsKey(service.getNamespaceId())) {//如果還沒有命名空間就增加命名一個空間
synchronized (putServiceLock) {
if (!serviceMap.containsKey(service.getNamespaceId())) {
serviceMap.put(service.getNamespaceId(), new ConcurrentHashMap<>(16));
}
}
}
serviceMap.get(service.getNamespaceId()).put(service.getName(), service);//放到命名空間裏
}
Service的init初始化和開啓心跳檢測
服務初始化,開啓一個心跳檢測,檢測所有的服務實例是否還在,延遲5
秒,間隔5
秒一次。
private ClientBeatCheckTask clientBeatCheckTask = new ClientBeatCheckTask(this);
public void init() {
//心跳檢查,延遲5秒,間隔5秒
HealthCheckReactor.scheduleCheck(clientBeatCheckTask);
for (Map.Entry<String, Cluster> entry : clusterMap.entrySet()) {
entry.getValue().setService(this);
entry.getValue().init();
}
}
HealthCheckReactor的scheduleCheck
開啓一個延遲5
秒,間隔5
秒的心跳任務,具體幹什麼的後面說,然後結果放進futureMap
中,後續可以取消操作。
private static Map<String, ScheduledFuture> futureMap = new ConcurrentHashMap<>();
public static void scheduleCheck(ClientBeatCheckTask task) {
futureMap.putIfAbsent(task.taskKey(), EXECUTOR.scheduleWithFixedDelay(task, 5000, 5000, TimeUnit.MILLISECONDS));
}
DelegateConsistencyServiceImpl的listen
代理了臨時和永久兩個服務,如果是特殊的com.alibaba.nacos.naming.domains.meta.
就直接註冊到永久一致性服務和臨時一致性服務裏。否則的話就看是臨時的服務還是永久的,選一個註冊進去。
@Override
public void listen(String key, RecordListener listener) throws NacosException {
// this special key is listened by both:
if (KeyBuilder.SERVICE_META_KEY_PREFIX.equals(key)) {//特殊前綴key兩個都監聽
persistentConsistencyService.listen(key, listener);
ephemeralConsistencyService.listen(key, listener);
return;
}
mapConsistencyService(key).listen(key, listener);//添加監聽器,添加到臨時或者永久的一致性服務的監聽器中
}
二選一:
private ConsistencyService mapConsistencyService(String key) {
return KeyBuilder.matchEphemeralKey(key) ? ephemeralConsistencyService : persistentConsistencyService;
}
Service
實現了監聽器接口:
DistroConsistencyServiceImpl的listen臨時的
其實就是創建一個CopyOnWriteArrayList
集合和key
的映射,這個集合是可同時讀寫的,寫的時候會複製一份來寫,寫完再替換舊的,此時讀的可能是舊的數據。然後將key監聽器放到集合離去。
@Override
public void listen(String key, RecordListener listener) throws NacosException {
if (!listeners.containsKey(key)) {//創建CopyOnWriteArrayList
listeners.put(key, new CopyOnWriteArrayList<>());
}
//二次確認不重複添加
if (listeners.get(key).contains(listener)) {
return;
}
//添加到創建CopyOnWriteArrayList
listeners.get(key).add(listener);
}
ServiceManager的addInstance添加實例
服務創建好了,監聽也加好了,接下來就要添加實例了。這裏再次獲取一次,看是不是爲空,空說明可能沒心跳被移除了。
如果存才的話添加實例:
public void addInstance(String namespaceId, String serviceName, boolean ephemeral, Instance... ips) throws NacosException {
//獲得服務實例key
String key = KeyBuilder.buildInstanceListKey(namespaceId, serviceName, ephemeral);
//再次獲取服務
Service service = getService(namespaceId, serviceName);
//這裏再判斷下service是否爲null比較好,因爲可能這個時候也爲空,synchronized鎖空對象會報異常,空對象沒monitor了
synchronized (service) {
//獲取所有該服務的實例
List<Instance> instanceList = addIpAddresses(service, ephemeral, ips);
Instances instances = new Instances();
instances.setInstanceList(instanceList);//設置到包裝對象裏
//放進一致性服務裏,其實就是放進臨時一致性服務內
consistencyService.put(key, instances);
}
}
具體的裏面細節下次說吧。
好了,今天就到這裏了,希望對學習理解有幫助,大神看見勿噴,僅爲自己的學習理解,能力有限,請多包涵。