Nacos(一)原始碼分析Nacos註冊示例流程

努力的小雨發表於2020-12-26

nacos官方地址:https://nacos.io/zh-cn/

大家可以看一下nacos的中文手冊以及官方原始碼,博主就不帶領大家快速入門 了,官方文件中都有而且非常標準,比其他部落格寫的好多了並且還是實時更新的。

先看一下博主給大家畫的流程圖,掌握一下大概的基本流程,好理解,博主給大家講原始碼:

https://www.processon.com/view/link/5f7e895be0b34d0711f65178

nacos最主要的功能就是服務註冊及發現,那它到底是如何實現的呢?博主用的springboot開發的,所以直接就去找nacos的jar包下的spring.factories,這是每個要自動注入的服務jar的必備檔案,我們來看一下

 

 

   裡面有很多的自動配置類,我們只看一下NacosServiceRegistryAutoConfiguration,該類主要做的是服務註冊的相關事宜,如果大家第一次看原始碼的話不知道該如何下手,最笨的方法就是一個一個看。總會找到的,最好要找名字看起來就像自己找的,因為這是阿里巴巴開發的,他們是有java開發規範的,要做到見名知意。

 1  /**
 2      * @author xiaojing
 3      * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 4      */
 5     @Configuration(proxyBeanMethods = false)
 6     @EnableConfigurationProperties
 7     @ConditionalOnNacosDiscoveryEnabled
 8     @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
 9             matchIfMissing = true)
10     @AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
11             AutoServiceRegistrationAutoConfiguration.class,
12             NacosDiscoveryAutoConfiguration.class })
13     public class NacosServiceRegistryAutoConfiguration {
14 
15         @Bean
16         public NacosServiceRegistry nacosServiceRegistry(
17                 NacosDiscoveryProperties nacosDiscoveryProperties) {
18             return new NacosServiceRegistry(nacosDiscoveryProperties);
19         }
20 
21         @Bean
22         @ConditionalOnBean(AutoServiceRegistrationProperties.class)
23         public NacosRegistration nacosRegistration(
24                 NacosDiscoveryProperties nacosDiscoveryProperties,
25                 ApplicationContext context) {
26             return new NacosRegistration(nacosDiscoveryProperties, context);
27         }
28 
29         @Bean
30         @ConditionalOnBean(AutoServiceRegistrationProperties.class)
31         public NacosAutoServiceRegistration nacosAutoServiceRegistration(
32                 NacosServiceRegistry registry,
33                 AutoServiceRegistrationProperties autoServiceRegistrationProperties,
34                 NacosRegistration registration) {
35             //這裡才是自動注入的類,我們需要進去看一下
36             return new NacosAutoServiceRegistration(registry,
37                     autoServiceRegistrationProperties, registration);
38         }
39 
40     }
 1 public class NacosAutoServiceRegistration
 2         extends AbstractAutoServiceRegistration<Registration> {
 3 
 4     private static final Logger log = LoggerFactory
 5             .getLogger(NacosAutoServiceRegistration.class);
 6 
 7     private NacosRegistration registration;
 8 
 9     public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry,
10             AutoServiceRegistrationProperties autoServiceRegistrationProperties,
11             NacosRegistration registration) {
12         super(serviceRegistry, autoServiceRegistrationProperties);
13         this.registration = registration;
14     }
15 
16     @Deprecated
17     public void setPort(int port) {
18         getPort().set(port);
19     }
20 
21     @Override
22     protected NacosRegistration getRegistration() {
23         if (this.registration.getPort() < 0 && this.getPort().get() > 0) {
24             this.registration.setPort(this.getPort().get());
25         }
26         Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set");
27         return this.registration;
28     }
29 
30     @Override
31     protected NacosRegistration getManagementRegistration() {
32         return null;
33     }
34 
35     @Override
36     protected void register() {
37         if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
38             log.debug("Registration disabled.");
39             return;
40         }
41         if (this.registration.getPort() < 0) {
42             this.registration.setPort(getPort().get());
43         }
44         super.register();
45     }
46 
47     @Override
48     protected void registerManagement() {
49         if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
50             return;
51         }
52         super.registerManagement();
53 
54     }
55 
56     @Override
57     protected Object getConfiguration() {
58         return this.registration.getNacosDiscoveryProperties();
59     }
60 
61     @Override
62     protected boolean isEnabled() {
63         return this.registration.getNacosDiscoveryProperties().isRegisterEnabled();
64     }
65 
66     @Override
67     @SuppressWarnings("deprecation")
68     protected String getAppName() {
69         String appName = registration.getNacosDiscoveryProperties().getService();
70         return StringUtils.isEmpty(appName) ? super.getAppName() : appName;
71     }
72 
73 }
看到這裡,大家可能有點懵,我應該找那個方法呢?大家可以看一下構造器中,引用了父類,當我們看到父類的時候,發現父類實現了ApplicationListener,這個類大家不陌生,系統會自動執行其onApplicationEvent而正好我們的類實現了這個方法,最後我們發現了應該看register() 方法,大家可以來看看這個方法的實現
 1 @Override
 2     public void register(Registration registration) {
 3 
 4         if (StringUtils.isEmpty(registration.getServiceId())) {
 5             log.warn("No service to register for nacos client...");
 6             return;
 7         }
 8         //看到這兩個引數,大家看過nacos文件就知道這兩個引數要幹啥用了
 9         String serviceId = registration.getServiceId();
10         String group = nacosDiscoveryProperties.getGroup();
11         //要傳送的例項物件,具體的屬性,大家可以看看這個方法
12         Instance instance = getNacosInstanceFromRegistration(registration);
13 
14         try {
15         //走這裡,是真正的註冊服務
16             namingService.registerInstance(serviceId, group, instance);
17             log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,
18                     instance.getIp(), instance.getPort());
19         }
20         catch (Exception e) {
21             log.error("nacos registry, {} register failed...{},", serviceId,
22                     registration.toString(), e);
23             // rethrow a RuntimeException if the registration is failed.
24             // issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132
25             rethrowRuntimeException(e);
26         }
27     }
 1     @Override
 2     public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
 3          //是否是臨時的,這個引數預設是臨時例項,這個是臨時或者是否持久很重要,先記住
 4         if (instance.isEphemeral()) {
 5             //填寫各種心跳資訊,畢竟服務需要往nacos傳送心跳,nacos才能知道該服務是否還存活
 6             BeatInfo beatInfo = new BeatInfo();
 7             beatInfo.setServiceName(NamingUtils.getGroupedName(serviceName, groupName));
 8             beatInfo.setIp(instance.getIp());
 9             beatInfo.setPort(instance.getPort());
10             beatInfo.setCluster(instance.getClusterName());
11             beatInfo.setWeight(instance.getWeight());
12             beatInfo.setMetadata(instance.getMetadata());
13             beatInfo.setScheduled(false);
14             beatInfo.setPeriod(instance.getInstanceHeartBeatInterval());
15             //看一下客服端是如何傳送心跳
16             beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), beatInfo);
17         }
18         //註冊服務
19         serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);
20     }
 1         @Override
 2         public void run() {
 3             if (beatInfo.isStopped()) {
 4                 return;
 5             }
 6             long nextTime = beatInfo.getPeriod();
 7             try {
 8                 //會呼叫nacos服務端的/instance/beat介面
 9                 JSONObject result = serverProxy.sendBeat(beatInfo, BeatReactor.this.lightBeatEnabled);
10                 long interval = result.getIntValue("clientBeatInterval");
11                 boolean lightBeatEnabled = false;
12                 if (result.containsKey(CommonParams.LIGHT_BEAT_ENABLED)) {
13                     lightBeatEnabled = result.getBooleanValue(CommonParams.LIGHT_BEAT_ENABLED);
14                 }
15                 BeatReactor.this.lightBeatEnabled = lightBeatEnabled;
16                 if (interval > 0) {
17                     nextTime = interval;
18                 }
19                 int code = NamingResponseCode.OK;
20                 if (result.containsKey(CommonParams.CODE)) {
21                     code = result.getIntValue(CommonParams.CODE);
22                 }
23                 //如果找不到服務,則進行註冊服務
24                 if (code == NamingResponseCode.RESOURCE_NOT_FOUND) {
25                     Instance instance = new Instance();
26                     instance.setPort(beatInfo.getPort());
27                     instance.setIp(beatInfo.getIp());
28                     instance.setWeight(beatInfo.getWeight());
29                     instance.setMetadata(beatInfo.getMetadata());
30                     instance.setClusterName(beatInfo.getCluster());
31                     instance.setServiceName(beatInfo.getServiceName());
32                     instance.setInstanceId(instance.getInstanceId());
33                     instance.setEphemeral(true);
34                     try {
35                         //該方法封裝好引數後,會呼叫/instance介面
36                         serverProxy.registerService(beatInfo.getServiceName(),
37                             NamingUtils.getGroupName(beatInfo.getServiceName()), instance);
38                     } catch (Exception ignore) {
39                     }
40                 }
41             } catch (NacosException ne) {
42                 NAMING_LOGGER.error("[CLIENT-BEAT] failed to send beat: {}, code: {}, msg: {}",
43                     JSON.toJSONString(beatInfo), ne.getErrCode(), ne.getErrMsg());
44 
45             }
46             //定時執行緒池不會一直迴圈進行呼叫,所以每次執行完之後會繼續新增定時任務進行傳送心跳
47             executorService.schedule(new BeatTask(beatInfo), nextTime, TimeUnit.MILLISECONDS);
48         }

  看完傳送心跳的方法,我們該看註冊服務的方法了:serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);其實就是傳送心跳後,找不到服務時調用的/instance介面。

  到此,我們的服務就會註冊到nacos服務端中,客戶端的程式碼就是如此,還是挺簡單的,我們下一篇就會帶大家走進服務端的程式碼。


 

相關文章