Nacos作为注册中心-源码解析

本文详细解析了Nacos作为注册中心的工作原理,包括客户端如何注册服务,服务端如何处理注册请求,服务发现的过程以及心跳机制。在服务注册中,Spring Cloud通过调用Nacos API完成服务注册;服务端接收到请求后,将服务信息存储并进行健康检查。服务发现则在客户端启动时自动进行,通过定时任务从Nacos服务端获取服务信息,并使用负载均衡算法选择服务进行调用。
摘要由CSDN通过智能技术生成

写在前面

源码的解读比较枯燥,但是能了解其原理。反复解读能理解他本质的思想,可以下载源码跟着我的顺序来解读。
第一次写文章,望各位大神指点其不足,部分源码比较简单只在外面加了注释没有进行详细解读,有兴趣可以跟下去看。

源码下载

naocs客户端源码 https://github.com/spring-cloud-incubator/spring-cloud-alibaba.
naocs服务端源码 https://github.com/alibaba/nacos.
nacos 官方API 文档 https://nacos.io/en-us/docs/open-api.html.
本文分析以下几个部分
1.客户端注册服务
2.服务端注册服务处理
3.客户端服务发现和调用过程
4.服务端返回客户端请求服务
5.服务心跳 定时

服务注册

spring cloud 是怎么样调用到 nacos的注册服务方法?

spring cloud 调用到 nacos的注册方法时序图
1.spring boot 启动后调用到 AnnotationConfigApplicationContext 下的 AnnotationConfigApplicationContext(Class<?>… componentClasses) 构造方法,然后调用refresh方法,refresh下的 finishRefresh()方法是我们调用注册服务的一步

		/**
		 * 这里由于他有父类,所以会先调用父类的构造方法:
		 * 看源码得知初始化了DefaultListableBeanFactory
		 *
		 * 然后才调用自己的构造方法:
		 * 1.创建一个读取注解的Bean定义读取器
		 * 	将bean读取完后,会调用DefaultListableBeanFactory注册这个bean
		 * 2.创建BeanDefinition扫描器
		 *  可以用来扫描包或者类,继而转换为bd
		 */
	public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
   
		this();
		register(componentClasses);
		refresh();
	}
public void refresh() throws BeansException, IllegalStateException {
   
		synchronized (this.startupShutdownMonitor) {
   
			/**
			 * 准备工作:
			 * 设置启动时间、是否激活标识位
			 * 初始化属性源(property source)配置
			 */
			prepareRefresh();
			/**
			 * 告诉子类刷新内部bean工厂
			 * 拿到DefaultListableBeanFactory,供后面方法调用
			 */
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			/**
			 * 准备bean工厂
			 */
			prepareBeanFactory(beanFactory);

			try {
   
				/**
				 * 这个方法在当前版本没有实现
				 * 可能在spring后面的版本会去扩展
				 */
				postProcessBeanFactory(beanFactory);
				/**
				 * 在上下文中调用注册为bean的工厂处理器
				 *
				 * 添加BeanPostProcessor
				 * 如果发现loadTimeWeaver的Bean
				 */
				invokeBeanFactoryPostProcessors(beanFactory);
				
				/**
				 * 注册BeanPostProcessor
				 * 自定义以及spring内部的
				 */
				registerBeanPostProcessors(beanFactory);
				
				/**
				 * 国际化支持,不关心
				 */
				initMessageSource();
				
				/**
				 * 初始化事件监听多路广播器
				 */
				initApplicationEventMulticaster();
				/**
				 * 这个方法在当前版本没有实现
				 * 可能在spring后面的版本会去扩展
				 */
				onRefresh();
				
				/**
				 * 注册监听器
				 */
				registerListeners();
				
				/**
				 * 实例化所有bean
				 */
				finishBeanFactoryInitialization(beanFactory);

				/**
				 * 发布事件
				 */
				finishRefresh();
			}
			......
		}
	}

2.finishRefresh推送ServletWebServerInitializedEven事件,AbstractAutoServiceRegistration触发监听并执行服务注册

/*
* serverler执行最后的容易刷新,并推送 ServletWebServerInitializedEvent监听事件
*/
	protected void finishRefresh() {
   
		super.finishRefresh();
		WebServer webServer = startWebServer();
		if (webServer != null) {
   
			publishEvent(new ServletWebServerInitializedEvent(webServer, this));
		}
	}
/*
* 监听器监听到 WebServerInitializedEvent 执行bind方法
*/
	public void onApplicationEvent(WebServerInitializedEvent event) {
   
		bind(event);
	}

	@Deprecated
	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();
	}
/*
* 1.推送实例注册前事件
* 2.推送注册前瑟吉欧款
* 3.执行注册后事件
* 4.重置启动状态
*/
	public void start() {
   
		/*注册的开关是否打开,如果只订阅是不需要打开的,这里取的是NacosDiscoveryProperties的参数*/
		if (!isEnabled()) {
   
			if (logger.isDebugEnabled()) {
   
				logger.debug("Discovery Lifecycle disabled. Not starting");
			}
			return;
		}

		/*容器未启动,即第一次启动的时候*/
		if (!this.running.get()) {
   
			
			this.context.publishEvent(
					new InstancePreRegisteredEvent(this, getRegistration()));
					
			/*注册服务,这里是调用NacosAutoServiceRegistration*/
			register();
			/*是否需要将管理服务的服务注册到注册中心,nacos的话是null,这里可以忽略*/
			if (shouldRegisterManagement()) {
   
				registerManagement();
			}
			this.context.publishEvent(
					new InstanceRegisteredEvent<>(this, getConfiguration()));
					
			/*启动状态更新*/		
			this.running.compareAndSet(false, true);
		}

	}

3.调用到NacosAutoServiceRegistration的register() 方法

客户端是怎么将服务注册到Nacos上的

承接上面的调用链>>>>>>>
naocs客户端调用链

1.NacosAutoServiceRegistration执行register()方法,然后调用父类 AbstractAutoServiceRegistration register()方法

	protected void register() {
   
		/*如果未开启注册到nacos,直接返回*/
		if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
   
			log.debug("Registration disabled.");
			return;
		}
		/*参数配置的端口小于0),获取服务端口,所以不需要去主动配置这个参数,可以根据服务的端口字段获取*/
		if (this.registration.getPort() < 0) {
   
			this.registration.setPort(getPort().get());
		}
		/*调用父类注册方法*/
		super.register();
	}

	protected void register() {
   
		this.serviceRegistry.register(getRegistration());
	}

2.NacosNamingService执行registerInstance方法

    public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
   
		/*临时实例*/
        if (instance.isEphemeral()) {
   
            BeatInfo beatInfo = new BeatInfo();
            beatInfo.setServiceName(NamingUtils.getGroupedName(serviceName, groupName));
            beatInfo.setIp(instance.getIp());
            beatInfo.setPort(instance.getPort());
            beatInfo.setCluster(instance.getClusterName());
            beatInfo.setWeight(instance.getWeight());
            beatInfo.setMetadata(instance.getMetadata());
            beatInfo.setScheduled(false);
            beatInfo.setPeriod(instance.getInstanceHeartBeatInterval());

            beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), beatInfo);
        }
		/*注册服务*/
        serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);
    }

3.NamingProxy执行registerService方法,调用reqAPI进行http请求"/nacos/v1/ns/instance"

    public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
   

        NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance: {}",
            namespaceId, serviceName, instance);
		/*拼接调用参数*/
        final Map<String, String> params = new HashMap<String, String>(9);
        params.put(CommonParams.NAMESPACE_ID, namespaceId);
        params.put(CommonParams.SERVICE_NAME, serviceName);
        params.put(CommonParams.GROUP_NAME, groupName);
        params.put(CommonParams.CLUSTER_NAME, instance.getClusterName());
        params.put("ip", instance.getIp());
        params.put("port", String.valueOf(instance.getPort()));
        params.put("weight", String.valueOf(instance.getWeight()));
        params.put("enable", String.valueOf(instance.isEnabled()));
        params.put("healthy", String.valueOf(instance.isHealthy()));
        params.put("ephemeral", String.valueOf(instance.isEphemeral()));
        params.put("metadata", JSON.toJSONString(instance.getMetadata()));
		/*发送服务注册请求*/
        reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, HttpMethod.POST);

    }
public String reqAPI(String api, Map<String, String> params, String body, List<String> servers, String method) throws NacosException {
   

		//获取命名空间id
        params.put(CommonParams.NAMESPACE_ID, getNamespaceId());
		//注册服务不能为空
        if (CollectionUtils.isEmpty(servers) && StringUtils.isEmpty(nacosDomain)) {
   
            throw new NacosException(NacosException.INVALID_PARAM, "no server available");
        }

        NacosException exception = new NacosException();
		
        if (servers != null && !servers.isEmpty()) {
   

            Random random = new Random(System.currentTimeMillis());
            int index = random.nextInt(servers.size());

            for (int i = 0; i < servers.size(); i++) {
   
                String server = servers.get(index);
                try {
   
   		 			//发送服务端请求
                    return callServer(api, params, body, server, method);
			······
    public String callServer(String api, Map<String, String> params, String body, String curServer, String method)
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值