首页 > 编程语言 >Nacos1.4源码(1):客户端注册源码

Nacos1.4源码(1):客户端注册源码

时间:2022-12-27 18:45:19浏览次数:60  
标签:Nacos1.4 String nacos instance 源码 params 注册 客户端

搭建环境

搭建Nacos服务端环境

从github上下载nacos1.4源码下来:https://github.com/alibaba/nacos

下载下来,源码编译好,直接idea运行 com.alibaba.nacos.Nacos类就行:

image-20221227172328481

那我怎么知道这个类就是启动类呢?

我们可以分析nacos的启动脚本,会java -jar名称为nacos-server.jar的jar包,然后解压该jar,看MANIFEST.MF文件,里面就描述了start-class为 com.alibaba.nacos.Nacos

在本篇文章中不需要研究nacos server端的源码,但是后面需要,所以就提前搭建好这个环境。

搭建nacos client环境

准备一个简单的springboot 项目:

    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

主启动类:

@EnableDiscoveryClient
@SpringBootApplication
public class NacosMainApplication {
    public static void main(String[] args) {
        SpringApplication.run(NacosMainApplication.class, args);
    }
}

bootstrap.yml

spring:
  application:
    name: nacos-test
  cloud:
    nacos:
      discovery:
        server-addr: 2.0.0.1:8848
        #设置命名空间
        namespace: public
        #设置服务实例是否持久化,true为AP模式,false为CP模式
        ephemeral: true
server:
  port: 10000

直接启动,发现服务可以注册到nacos:

image-20221227173357831

源码分析

spring cloud commons服务注册规范

在我们引入nacos-discovery的starter的时候,会自动引入spring-cloud-commons,而该包中就有spring cloud对微服务制定的一些接口规范,如果想要接入springcloud,就必须实现该规范。

image-20221227173904976

本文是将客户端注册源码,所以我们就先可以了解serviceregistry 服务注册的规范:

image-20221227174051719

主要有两大核心接口:RegistrationServiceRegistry

  • Registration:表示需要被注册的服务实例
  • ServiceRegistry:服务注册对象,通过此对象,可以向注册中心注册服务实例。

此外还有一个重要的自动注册器:AbstractAutoServiceRegistration,spring cloud的想法是第三方继承了抽象类并实现了注册方法,当前服务就可以自动发起注册。

那么是怎么做的呢:先看类图:

image-20221227174646957

比较引人注意的就是实现了ApplicationListener接口。我们接下来看源码:

	@Override
	@SuppressWarnings("deprecation")
	//监听WebServerInitializedEvent事件
        //该事件会在web容器启动完成后发出
	public void onApplicationEvent(WebServerInitializedEvent event) {
       	//执行bind方法
		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());
                //执行start方法
		this.start();
	}

	public void start() {
		if (!isEnabled()) {
			if (logger.isDebugEnabled()) {
				logger.debug("Discovery Lifecycle disabled. Not starting");
			}
			return;
		}

		// only initialize if nonSecurePort is greater than 0 and it isn't already running
		// because of containerPortInitializer below
		if (!this.running.get()) {
                        //发布服务实例注册前事件
			this.context.publishEvent(
					new InstancePreRegisteredEvent(this, getRegistration()));
           	        //调用注册方法
			register();
			if (shouldRegisterManagement()) {
				registerManagement();
			}
                        //发布服务实例注册完成事件
			this.context.publishEvent(
					new InstanceRegisteredEvent<>(this, getConfiguration()));
			this.running.compareAndSet(false, true);
		}

	}

	protected void register() {
                //执行serviceRegistry的register注册方法,serviceRegistry需要第三方自行实现
		this.serviceRegistry.register(getRegistration());
	}
	//获取到服务注册实例对象 
	protected abstract R getRegistration();

nacos对规范的实现

NacosAutoServiceRegistration是对AbstractAutoServiceRegistration抽象类的实现比较简单,而该类被自动注册类NacosServiceRegistryAutoConfiguration所引入:

public class NacosServiceRegistryAutoConfiguration {

    //创建NacosServiceRegistry,实现了ServiceRegistry接口,用于客户端向nacos服务端注册服务实例
	@Bean
	public NacosServiceRegistry nacosServiceRegistry(
			NacosDiscoveryProperties nacosDiscoveryProperties) {
		return new NacosServiceRegistry(nacosDiscoveryProperties);
	}

	@Bean
	@ConditionalOnBean(AutoServiceRegistrationProperties.class)
        //创建NacosRegistration,即所需要注册的服务实例对象
	public NacosRegistration nacosRegistration(
			ObjectProvider<List<NacosRegistrationCustomizer>> registrationCustomizers,
			NacosDiscoveryProperties nacosDiscoveryProperties,
			ApplicationContext context) {
		return new NacosRegistration(registrationCustomizers.getIfAvailable(),
				nacosDiscoveryProperties, context);
	}

	@Bean
	@ConditionalOnBean(AutoServiceRegistrationProperties.class)
        //创建NacosAutoServiceRegistration
	public NacosAutoServiceRegistration nacosAutoServiceRegistration(
			NacosServiceRegistry registry,
			AutoServiceRegistrationProperties autoServiceRegistrationProperties,
			NacosRegistration registration) {
		return new NacosAutoServiceRegistration(registry,
				autoServiceRegistrationProperties, registration);
	}

}

所以我们只需要研究NacosServiceRegistry类的register方法就能知道注册的源码了:

	@Override
	public void register(Registration registration) {

		if (StringUtils.isEmpty(registration.getServiceId())) {
			log.warn("No service to register for nacos client...");
			return;
		}
		//获取到NamingService,实际上nacos注册是靠NamingService
		NamingService namingService = namingService();
                //获取服务id
		String serviceId = registration.getServiceId();
                //获取group
		String group = nacosDiscoveryProperties.getGroup();
		//创建Instance对象,无非就是把registration的属性值设置到Instance中
		Instance instance = getNacosInstanceFromRegistration(registration);

		try {
                        //真正执行注册方法,注册Instance实例
			namingService.registerInstance(serviceId, group, instance);
			log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,
					instance.getIp(), instance.getPort());
		}
		catch (Exception e) {
			log.error("nacos registry, {} register failed...{},", serviceId,
					registration.toString(), e);
			// rethrow a RuntimeException if the registration is failed.
			// issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132
			rethrowRuntimeException(e);
		}
	}

	private NamingService namingService() {
        //从给定的Properties获取到NamingService
        //本质上就是获取Properties的属性内容,并设置到NacosNamingService成员变量中,做一些初始化属性的操作
		return nacosServiceManager
				.getNamingService(nacosDiscoveryProperties.getNacosProperties());
	}

再看registerInstance源码:

    @Override
    public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
        //校验Instance信息是否合法
        NamingUtils.checkInstanceIsLegal(instance);
        String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
        //判断实例是否是临时的,默认为true
        if (instance.isEphemeral()) {
            BeatInfo beatInfo = beatReactor.buildBeatInfo(groupedServiceName, instance);
            //添加心跳任务(这个心跳任务我们以后再说)
            beatReactor.addBeatInfo(groupedServiceName, beatInfo);
        }
        //调用NamingProxy的registerService进行注册
        serverProxy.registerService(groupedServiceName, groupName, instance);
    }

代码继续往里面走,这里就已经初见端倪了,直接调用rest请求进行注册的。

    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>(16);
        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", JacksonUtils.toJson(instance.getMetadata()));
        //执行POST请求方法
        //这里nacosUrlInstance拼起来就是:/nacos/v1/ns/instance
        reqApi(UtilAndComs.nacosUrlInstance, params, HttpMethod.POST);
        
    }

reqApi方法在往里面走,走到callServer方法:

    public String callServer(String api, Map<String, String> params, Map<String, String> body, String curServer,
            String method) throws NacosException {
        long start = System.currentTimeMillis();
        long end = 0;
        injectSecurityInfo(params);
        Header header = builderHeader();
        
        String url;
        if (curServer.startsWith(UtilAndComs.HTTPS) || curServer.startsWith(UtilAndComs.HTTP)) {
            url = curServer + api;
        } else {
            if (!IPUtil.containsPort(curServer)) {
                curServer = curServer + IPUtil.IP_PORT_SPLITER + serverPort;
            }
            url = NamingHttpClientManager.getInstance().getPrefix() + curServer + api;
        }
        
        try {
            //执行nacosRestTemplate的exchangeForm,发送http请求
            //nacosRestTemplate是Nacos自己实现的http 客户端,大家可以把他看作spring实现的RestTemplate,作用都是一样的
            HttpRestResult<String> restResult = nacosRestTemplate
                    .exchangeForm(url, header, Query.newInstance().initParams(params), body, method, String.class);
            end = System.currentTimeMillis();
            
            MetricsMonitor.getNamingRequestMonitor(method, url, String.valueOf(restResult.getCode()))
                    .observe(end - start);
            
            if (restResult.ok()) {
                return restResult.getData();
            }
            if (HttpStatus.SC_NOT_MODIFIED == restResult.getCode()) {
                return StringUtils.EMPTY;
            }
            throw new NacosException(restResult.getCode(), restResult.getMessage());
        } catch (Exception e) {
            NAMING_LOGGER.error("[NA] failed to request", e);
            throw new NacosException(NacosException.SERVER_ERROR, e);
        }
    }

客户端注册方法到这里全部走完。

因为客户端发送POST请求进行注册,所以服务端一定有对应的Controller进行处理。

而处理注册请求的Controller就是com.alibaba.nacos.naming.controllers.InstanceController,在之前下载的nacos server端的源码中:

image-20221227183403228

后面我会对nacos1.4服务端注册服务实例源码进行解析。

标签:Nacos1.4,String,nacos,instance,源码,params,注册,客户端
From: https://www.cnblogs.com/wwjj4811/p/17008755.html

相关文章