一、客戶端
代碼鏈路:
SpringBootApplication上使用註解@EnableDiscoveryClient --> @EnableDiscoveryClient 註解是用來啓用 DiscoveryClient(接口) 的實現(代碼類描述:Annotation to enable a DiscoveryClient implementation.)
--> EurekaDiscoveryClient中引用了 EurekaClient 類 --> EurekaClient的實現類 DiscoveryClient --> DiscoveryClient 的構造函數是服務註冊、服務續約、服務發現的入口
服務註冊整個過程總結:
S1:初始化操作 : 先調用了com.netflix.discovery.DiscoveryClient#getEurekaServiceUrlsFromConfig()方法,去獲取相關配置
S2:服務註冊 : com.netflix.discovery.DiscoveryClient 構造函數中調用了com.netflix.discovery.DiscoveryClient#initScheduledTasks方法
S3:initScheduledTasks方法中調用了異步註冊服務類InstanceInfoReplicator的start()方法,因爲InstanceInfoReplicator實現了Runnable接口,所以業務實現邏輯在run()方法中,在run()方法中調用了discoveryClient.register();
S4:服務註冊真正實現:httpResponse = eurekaTransport.registrationClient.register(instanceInfo);使用了http請求將元數據InstanceInfo請求到註冊中心。最後判斷httpResponse.getStatusCode() == 204返回布爾值
二、服務端
代碼鏈路:
SpringBootApplication上使用註解@EnableEurekaServer
--> EurekaServerAutoConfiguration 中通過@Bean註解初始化該對象PeerAwareInstanceRegistry(接口),真正邏輯在實現類中
--> PeerAwareInstanceRegistryImpl#register()調用父類註冊方法super.register(info, leaseDuration, isReplication);
--> AbstractInstanceRegistry#register(InstanceInfo registrant, int leaseDuration, boolean isReplication
只對服務註冊邏輯源碼閱讀總結:PeerAwareInstanceRegistryImpl#register(final InstanceInfo info, final boolean isReplication)
S1: 續約過期時間
1.1先判斷租約信息對象是否爲空,並且持續時間是否大於0
1.2如果上訴條件成立,取租約信息對象中的持續時間,否則取取租約信息對象中默認的持續時間,並且將持續時間傳遞到註冊方法中
S2:註冊應用實例信息
2.1 調用父類AbstractInstanceRegistry的register(InstanceInfo registrant, int leaseDuration, boolean isReplication)
註冊結構:private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry;第一層的key爲應用的AppName(InstanceInfo中這樣命名的,但含義就是服務的唯一id標識,所以這個服務名稱不能重複),第二層的key爲服務實例的InstanceId
com.netflix.appinfo.InstanceInfo:應用實例信息,LeaseInfo:應用實例信息的租約信息
2.2 進來,使用讀寫鎖Lock read = readWriteLock.readLock();先加鎖 read.lock();
2.3 根據AppName獲取到對應的Map<String, Lease<InstanceInfo>>多個應用實例信息爲gMap
2.4 如果gMap爲空,則生成一個新的key爲AppName的ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap
2.5 根據InstanceId獲取對應應用實例信息 existingLease
2.5.1 如果InstanceId存在,直接返回
2.5.2 如果InstanceId不存在,但DataCenterInfo中存在,則返回DataCenterInfo中的id
2.5.3 如果上訴兩者都不滿足,則直接返回hostName
2.6 註冊應用實例存在:如果existingLease不爲空,並且租約信息對應的持有者,即對應的應用實例也不爲空
2.7 註冊應用實例不存在:如果existingLease爲空,或者租約信息對應的持有者爲空
2.8 先構建Lease<InstanceInfo> lease租約信息對象,然後lease對象set值,最後把封裝好的lease對象put到gMap中
2.9 根據InstanceStatus的狀態不是unknown,則封裝ConcurrentMap<String, InstanceStatus>以instanceId爲key,InstanceStatus爲value的overriddenInstanceStatusMap
2.10 給InstanceInfo對象中set應用實例的狀態:
2.10.1 如果InstanceStatus不是空,則給InstanceInfo對象中set應用實例的狀態setOverriddenStatus
2.10.2 如果InstanceStatus是空,根據overridden status rules生成新的狀態並賦值給InstanceInfo對象的狀態字段setStatusWithoutDirty
2.11 給InstanceInfo對象中set應用實例的上線的其他字段信息: registrant.setActionType,registrant.setLastUpdatedTimestamp
2.12 釋放鎖 read.unlock();
S3: Eureka-Server間信息同步