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:[email protected]">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服務端中,客戶端的程式碼就是如此,還是挺簡單的,我們下一篇就會帶大家走進服務端的程式碼。
&n