• nacos服务注册源码过程阅读


    准备部分

    在这里插入图片描述

    这是在真正调用注册实例的方法之前,需要使用到的对象的关系图。

    源码跟踪

    NacosServiceRegistryAutoConfiguration类
    @Configuration(proxyBeanMethods = false)
    @EnableConfigurationProperties
    @ConditionalOnNacosDiscoveryEnabled
    @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
    		matchIfMissing = true)
    @AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
    		AutoServiceRegistrationAutoConfiguration.class,
    		NacosDiscoveryAutoConfiguration.class })
    public class NacosServiceRegistryAutoConfiguration {
    
    	@Bean
    	public NacosServiceRegistry nacosServiceRegistry(
    	 //  在spring.factories中,有个自动创建的类是 NacosServiceAutoConfiguration,这个类里创建了 NacosServiceManager 对象,也就是对应这里的第一个参数
    			NacosServiceManager nacosServiceManager, 
    			NacosDiscoveryProperties nacosDiscoveryProperties) {   //  取的配置文件
    		return new NacosServiceRegistry(nacosServiceManager, nacosDiscoveryProperties);
    	}
    
    	@Bean
    	@ConditionalOnBean(AutoServiceRegistrationProperties.class)
    	public NacosRegistration nacosRegistration(
    			ObjectProvider> registrationCustomizers,  // 不知道是个啥,感觉不是重点所以没看
    			NacosDiscoveryProperties nacosDiscoveryProperties,  // 配置文件
    			ApplicationContext context) {   // spring容器创建的
    		return new NacosRegistration(registrationCustomizers.getIfAvailable(),
    				nacosDiscoveryProperties, context);
    	}
    
    	@Bean
    	@ConditionalOnBean(AutoServiceRegistrationProperties.class)
    	这个是才是重点对象
    	public NacosAutoServiceRegistration nacosAutoServiceRegistration(
    			NacosServiceRegistry registry,  // 上面第一个方法创建的Bean
    			AutoServiceRegistrationProperties autoServiceRegistrationProperties,    // 取的配置文件中的值
    			NacosRegistration registration) {  // 上面第二个方法创建的Bean
    		return new NacosAutoServiceRegistration(registry,
    				autoServiceRegistrationProperties, registration);
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    AbstractAutoServiceRegistration类

    直接看NacosAutoServiceRegistration继承的这个抽象类

    	@Override
    	@SuppressWarnings("deprecation")
    	//  NacosAutoServiceRegistration类有实现ApplicationListener,所以会监听到WebServerInitializedEvent事件
    	public void onApplicationEvent(WebServerInitializedEvent event) {
    		bind(event);
    	}
    
    
    	public void bind(WebServerInitializedEvent event) {
    		ApplicationContext context = event.getApplicationContext();
    		if (context instanceof ConfigurableWebServerApplicationContext) {
    			if ("management".equals(((ConfigurableWebServerApplicationContext) context).getServerNamespace())) {
    				return;
    			}
    		}
    		this.port.compareAndSet(0, event.getWebServer().getPort());
    		this.start();
    	}
    	
    
    public void start() {
    		if (!isEnabled()) {
    			if (logger.isDebugEnabled()) {
    				logger.debug("Discovery Lifecycle disabled. Not starting");
    			}
    			return;
    		}
    
    		if (!this.running.get()) {
    		//  NacosServiceManager类中的 onInstancePreRegisteredEvent 方法上有@EventListener,会监听到这个预注册事件,具体不知道逻辑,看变量名称好像缓存		    	                  用的
    			this.context.publishEvent(new InstancePreRegisteredEvent(this, getRegistration()));
    			// 会调用register方法
    			register();
    			if (shouldRegisterManagement()) {
    				registerManagement();
    			}
    			this.context.publishEvent(new InstanceRegisteredEvent<>(this, getConfiguration()));
    			this.running.compareAndSet(false, true);
    		}
    
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    NacosServiceRegistry类

    一直溯源register方法,会看到NacosServiceRegistry类中的register(Registration registration)方法,

    @Override
    	public void register(Registration registration) {
    
    		if (StringUtils.isEmpty(registration.getServiceId())) {
    			log.warn("No service to register for nacos client...");
    			return;
    		}
    		//  这里的namingService()溯源会看到创建这个NamingService 用到了反射
    		NamingService namingService = namingService();
    		// serviceId 其实就是spring.application.name值
    		String serviceId = registration.getServiceId();
    		String group = nacosDiscoveryProperties.getGroup();
    		
    		// 直接new一个Instance对象
    		Instance instance = getNacosInstanceFromRegistration(registration);
    
    		try {
    			namingService.registerInstance(serviceId, group, instance);
    			log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,
    					instance.getIp(), instance.getPort());
    		}
    		catch (Exception e) {
    			if (nacosDiscoveryProperties.isFailFast()) {
    				log.error("nacos registry, {} register failed...{},", serviceId,
    						registration.toString(), e);
    				rethrowRuntimeException(e);
    			}
    			else {
    				log.warn("Failfast is false. {} register failed...{},", serviceId,
    						registration.toString(), e);
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    创建NamingService的具体代码:

        public static NamingService createNamingService(Properties properties) throws NacosException {
            try {
                Class driverImplClass = Class.forName("com.alibaba.nacos.client.naming.NacosNamingService");
                Constructor constructor = driverImplClass.getConstructor(Properties.class);
                NamingService vendorImpl = (NamingService)constructor.newInstance(properties);
                return vendorImpl;
            } catch (Throwable var4) {
                throw new NacosException(-400, var4);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    NacosNamingService类
        public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
        //  这里校验的就是配置的心跳间隔和心跳超时,ip删除超时三个参数的值的大小关系,心跳间隔必须比这两个都要小
            NamingUtils.checkInstanceIsLegal(instance);
            String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
            //  如果是临时实例,就会开一个心跳线程,不设置事件默认应该是5s的延迟
            if (instance.isEphemeral()) {
                BeatInfo beatInfo = this.beatReactor.buildBeatInfo(groupedServiceName, instance);
                this.beatReactor.addBeatInfo(groupedServiceName, beatInfo);
            }
    
            this.serverProxy.registerService(groupedServiceName, groupName, instance);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    NamingProxy类
        public String callServer(String api, Map params, Map body, String curServer, String method) throws NacosException {
            long start = System.currentTimeMillis();
            long end = 0L;
            this.injectSecurityInfo(params);
            Header header = this.builderHeader();
            String url;
            if (!curServer.startsWith("https://") && !curServer.startsWith("http://")) {
                if (!IPUtil.containsPort(curServer)) {
                    curServer = curServer + ":" + this.serverPort;
                }
    
                url = NamingHttpClientManager.getInstance().getPrefix() + curServer + api;
            } else {
                url = curServer + api;
            }
    
            try {
            // 这里的nacosRestTemplate 点进去溯源之后会发现 
                HttpRestResult restResult = this.nacosRestTemplate.exchangeForm(url, header, Query.newInstance().initParams(params), body, method, String.class);
                end = System.currentTimeMillis();
                MetricsMonitor.getNamingRequestMonitor(method, url, String.valueOf(restResult.getCode())).observe((double)(end - start));
                if (restResult.ok()) {
                    return (String)restResult.getData();
                } else if (304 == restResult.getCode()) {
                    return "";
                } else {
                    throw new NacosException(restResult.getCode(), restResult.getMessage());
                }
            } catch (Exception var13) {
                LogUtils.NAMING_LOGGER.error("[NA] failed to request", var13);
                throw new NacosException(500, var13);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    // 先是在NamingProxy中显式创建NacosRestTemplate 对象
    private final NacosRestTemplate nacosRestTemplate = NamingHttpClientManager.getInstance().getNacosRestTemplate();
    
    
    NamingHttpClientManager类
    
    //  这里传入的参数其实是NamingHttpClientFactory对象,并且这个对象是继承了AbstractHttpClientFactory抽象类的
        public NacosRestTemplate getNacosRestTemplate() {
            return HttpClientBeanHolder.getNacosRestTemplate(HTTP_CLIENT_FACTORY);
        }
    
    
    HttpClientBeanHolder类
    
      public static NacosRestTemplate getNacosRestTemplate(HttpClientFactory httpClientFactory) {
            if (httpClientFactory == null) {
                throw new NullPointerException("httpClientFactory is null");
            }
            String factoryName = httpClientFactory.getClass().getName();
            NacosRestTemplate nacosRestTemplate = SINGLETON_REST.get(factoryName);
            if (nacosRestTemplate == null) {
                synchronized (SINGLETON_REST) {
                    nacosRestTemplate = SINGLETON_REST.get(factoryName);
                    if (nacosRestTemplate != null) {
                        return nacosRestTemplate;
                    }
                    //  如果SINGLETON_REST 这个集合中没有找到,会走到这个方法,会发现 参数传过来的 httpClientFactory是个接口,并且有两个实现类,分别是AbstractApacheHttpClientFactory和AbstractHttpClientFactory,因为知道入参其实就是NamingHttpClientFactory,并且继承了AbstractHttpClientFactory
                    nacosRestTemplate = httpClientFactory.createNacosRestTemplate();
                    SINGLETON_REST.put(factoryName, nacosRestTemplate);
                }
            }
            return nacosRestTemplate;
        }
    
    
    AbstractHttpClientFactory类
    
            HttpClientConfig httpClientConfig = buildHttpClientConfig();
            // 这里就知道NacosRestTemplate中的HttpClientRequest属性其实是  JdkHttpClientRequest实例对象,
            final JdkHttpClientRequest clientRequest = new JdkHttpClientRequest(httpClientConfig);
            
            // enable ssl
            initTls(new BiConsumer() {
                @Override
                public void accept(SSLContext sslContext, HostnameVerifier hostnameVerifier) {
                    clientRequest.setSSLContext(loadSSLContext());
                    clientRequest.replaceSSLHostnameVerifier(hostnameVerifier);
                }
            }, new TlsFileWatcher.FileChangeListener() {
                @Override
                public void onChanged(String filePath) {
                    clientRequest.setSSLContext(loadSSLContext());
                }
            });
            
            return new NacosRestTemplate(assignLogger(), clientRequest);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    NacosRestTemplate类

    在上面NamingProxy中一顿点击之后,会调用到NacosRestTemplate的execute方法,如下

        private  HttpRestResult execute(String url, String httpMethod, RequestHttpEntity requestEntity,
                Type responseType) throws Exception {
            URI uri = HttpUtils.buildUri(url, requestEntity.getQuery());
            if (logger.isDebugEnabled()) {
                logger.debug("HTTP method: {}, url: {}, body: {}", httpMethod, uri, requestEntity.getBody());
            }
            
            ResponseHandler responseHandler = super.selectResponseHandler(responseType);
            HttpClientResponse response = null;
            try {
            /// 上面溯源得到的  JdkHttpClientRequest  对应的就是this.requestClient(),因为上面可以看到调用NacosRestTemplate的构造函数,传入的是JdkHttpClientRequest  
                response = this.requestClient().execute(uri, httpMethod, requestEntity);
                return responseHandler.handle(response);
            } finally {
                if (response != null) {
                    response.close();
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    之后就是使用HttpURLConnection实际发情请求,并且处理Response了。

  • 相关阅读:
    前端实现Jest单元测试
    对xgboost进行可视化,解决中文乱码问题
    【Python】列表推导式创建列表
    【Vue】父子组件间如何通过事件进行通信(1)
    you need to install the latest version of Visual Studio
    2113_扫雷 蓝桥杯
    一键智能视频语音转文本——基于PaddlePaddle语音识别与Python轻松提取视频语音并生成文案
    LeetCode 2609. 最长平衡子字符串
    如何通过EasyCVR接口监测日志观察平台拉流情况?
    使用两个goroutine交替、顺序打印一段字符串的字符
  • 原文地址:https://blog.csdn.net/ZRL1996/article/details/127932859