nacos-注册源码剖析

一. 根据pom依赖 找到注册主类

  1. 找到自动装配类
    使用nacos注册, 我们都会在pom里添加nacos-discovery依赖

<dependency>
    <groupId>com.alibaba.cloudgroupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
  1. 在依赖里找到这个jar包, 再找到spring.factories, 如下
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration,\
  com.alibaba.cloud.nacos.ribbon.RibbonNacosAutoConfiguration,\
  com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,\
  com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration,\
  com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\
  com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration,\
  com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration,\
  com.alibaba.cloud.nacos.NacosServiceAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
  com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration

  1. 找到一个Nacos服务注册自动装配类 --> NacosServiceRegistryAutoConfiguration, 接下来从这个类看注册

二. 源码解析NacosServiceRegistryAutoConfiguration

大胆猜测: 看源码之前大致猜想一下, 既然是一个注册的jar, 那么他的业务逻辑起码应该是: 第一步: springIOC初始化后类似dubbo注册一样, 有一个onApplicationEvent触发注册, 第二步: 根据已配置的yml参数, 往nacos注册中心里注册. 也往nacos注册中心留一条服务信息. 这样别的服务才能知道且调用过来. 相当于一个中介角色.

@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(
			NacosDiscoveryProperties nacosDiscoveryProperties) {
     
		return new NacosServiceRegistry(nacosDiscoveryProperties);
	}

	@Bean
	@ConditionalOnBean(AutoServiceRegistrationProperties.class)
	public NacosRegistration nacosRegistration(
			ObjectProvider<List<NacosRegistrationCustomizer>> registrationCustomizers,
			NacosDiscoveryProperties nacosDiscoveryProperties,
			ApplicationContext context) {
     
		return new NacosRegistration(registrationCustomizers.getIfAvailable(),
				nacosDiscoveryProperties, context);
	}

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

}
  1. NacosRegistration
public class NacosRegistration implements Registration, ServiceInstance {
     
	...

	// @PostConstruct初始化前这个时间断 执行该方法 可以看出来主要作用是 判断是否yml中有参数 往metadata中set
	@PostConstruct
	public void init() {
     

		Map<String, String> metadata = nacosDiscoveryProperties.getMetadata();
		Environment env = context.getEnvironment();

		String endpointBasePath = env.getProperty(MANAGEMENT_ENDPOINT_BASE_PATH);
		if (!StringUtils.isEmpty(endpointBasePath)) {
     
			metadata.put(MANAGEMENT_ENDPOINT_BASE_PATH, endpointBasePath);
		}

		Integer managementPort = ManagementServerPortUtils.getPort(context);
		if (null != managementPort) {
     
			metadata.put(MANAGEMENT_PORT, managementPort.toString());
			String contextPath = env
					.getProperty("management.server.servlet.context-path");
			String address = env.getProperty("management.server.address");
			if (!StringUtils.isEmpty(contextPath)) {
     
				metadata.put(MANAGEMENT_CONTEXT_PATH, contextPath);
			}
			if (!StringUtils.isEmpty(address)) {
     
				metadata.put(MANAGEMENT_ADDRESS, address);
			}
		}

		if (null != nacosDiscoveryProperties.getHeartBeatInterval()) {
     
			metadata.put(PreservedMetadataKeys.HEART_BEAT_INTERVAL,
					nacosDiscoveryProperties.getHeartBeatInterval().toString());
		}
		if (null != nacosDiscoveryProperties.getHeartBeatTimeout()) {
     
			metadata.put(PreservedMetadataKeys.HEART_BEAT_TIMEOUT,
					nacosDiscoveryProperties.getHeartBeatTimeout().toString());
		}
		if (null != nacosDiscoveryProperties.getIpDeleteTimeout()) {
     
			metadata.put(PreservedMetadataKeys.IP_DELETE_TIMEOUT,
					nacosDiscoveryProperties.getIpDeleteTimeout().toString());
		}
		customize(registrationCustomizers, this);
	}
	...
}
  1. AbstractAutoServiceRegistration
public abstract class AbstractAutoServiceRegistration<R extends Registration>
		implements AutoServiceRegistration, ApplicationContextAware,
		ApplicationListener<WebServerInitializedEvent> {
     
	...
	
	// 看到了这个方法 就知道是spring加载完成后要做的事情
	@Override
	@SuppressWarnings("deprecation")
	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;
			}
		}
		// CAS
		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;
		}

		// 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就会调用到第三个@Bean的NacosServiceRegistry里面的register方法
			// 接下来看NacosServiceRegistry的register方法实现
			register();
			if (shouldRegisterManagement()) {
     
				registerManagement();
			}
			this.context.publishEvent(
					new InstanceRegisteredEvent<>(this, getConfiguration()));
			this.running.compareAndSet(false, true);
		}

	}

	...
}
  1. NacosServiceRegistry
public class NacosServiceRegistry implements ServiceRegistry<Registration> {
     
	...

	@Override
	public void register(Registration registration) {
     

		if (StringUtils.isEmpty(registration.getServiceId())) {
     
			log.warn("No service to register for nacos client...");
			return;
		}
		// 1. 核心NamingService 主要看这个service的实例化
		NamingService namingService = namingService();
		String serviceId = registration.getServiceId();
		String group = nacosDiscoveryProperties.getGroup();

		Instance instance = getNacosInstanceFromRegistration(registration);

		try {
     
			// 调用实例化出来的namingService 的注册方法 http形式通知到nacos注册中心
			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);
		}
	}

	...

	// 2. 去nacosServiceManager里 拿namingService 接下来去看nacosServiceManager这个类
	private NamingService namingService() {
     
		return nacosServiceManager
				.getNamingService(nacosDiscoveryProperties.getNacosProperties());
	}
}
  1. NacosServiceManager
public class NacosServiceManager {
     
	...

	public NamingService getNamingService(Properties properties) {
     
		if (Objects.isNull(this.namingService)) {
     
			// 1. 看如何构建的
			buildNamingService(properties);
		}
		return namingService;
	}
	...

	private NamingService buildNamingService(Properties properties) {
     
		if (Objects.isNull(namingService)) {
     
			// sync 锁资源 避免重复build
			synchronized (NacosServiceManager.class) {
     
				if (Objects.isNull(namingService)) {
     
					namingService = createNewNamingService(properties);
				}
			}
		}
		return namingService;
	}
	...
	
	private NamingService createNewNamingService(Properties properties) {
     
		try {
     
			// 2. 源码包下api目录下, NamingFactory的createNamingService方法
			return createNamingService(properties);
		}
		catch (NacosException e) {
     
			throw new RuntimeException(e);
		}
	}

	...
}
  1. NamingFactory
public class NamingFactory{
     
	...
	
	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);
            // 这里会实例化出NaocsNamingService
            NamingService vendorImpl = (NamingService) constructor.newInstance(properties);
            return vendorImpl;
        } catch (Throwable e) {
     
            throw new NacosException(NacosException.CLIENT_INVALID_PARAM, e);
        }
    }
}
  1. NaocsNamingService
public class NaocsNamingService{
     
	...

	@Override
    public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
     
    	// 检查参数的有效性
        NamingUtils.checkInstanceIsLegal(instance);
        String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
        // 是否为临时的也就是AP架构 
        // nacos支持CAP里的两种架构 一种是AP架构存在内存的数据 另一种是CP架构 持久化到磁盘的
        if (instance.isEphemeral()) {
     
        	// 构建心跳实体
            BeatInfo beatInfo = beatReactor.buildBeatInfo(groupedServiceName, instance);
            // 添加到ScheduledThreadPoolExecutor里 定时发送心跳
            beatReactor.addBeatInfo(groupedServiceName, beatInfo);
        }
        // proxy的注册逻辑 接下来去NamingProxy看
        serverProxy.registerService(groupedServiceName, groupName, instance);
    }
	...
}
  1. NamingProxy
public class NamingProxy{
     
	...

	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()));
        
        // UtilAndComs.nacosUrlInstance        
        // public static String nacosUrlInstance = nacosUrlBase + "/instance";
		// nacosTemplate http形式 调用nacos注册中心的注册api
		// 就此注册到nacos注册中心上去了
        reqApi(UtilAndComs.nacosUrlInstance, params, HttpMethod.POST);
        
    }
	
	...
}

PS: 这里只是介绍了client的注册逻辑, nacos server主要是对外提供了一套api来实现注册与实例查询相关, 官网: https://nacos.io/en-us/docs/open-api.html

你可能感兴趣的:(微服务,spring,cloud,alibaba)