Nacos学习笔记(三):服务是如何自动注册的

一、前文回顾

在上一篇文章中我们学习了Nacos的注册逻辑,笔者在刚接触Nacos的时候就一直有个疑问,为什么我们的微服务(这里以Springboot为例)启动后就会自动注册到Nacos中,我们似乎也没有编写对应的方法去发送注册请求,带着这个疑问我们开始今天的源码学习。

二、源码分析

1、 Nacos自动装配

我们找到Nacos相关的依赖,如下图:
Nacos学习笔记(三):服务是如何自动注册的_第1张图片
可以看到在registry包下有一个 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(
			NacosDiscoveryProperties nacosDiscoveryProperties,
			NacosServiceManager nacosServiceManager) {
		return new NacosServiceRegistry(nacosDiscoveryProperties, nacosServiceManager);
	}

	@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、首先这个类加载的条件是
(1)spring.cloud.nacos.discovery.enabled(默认true)
(2)spring.cloud.service-registry.auto-registration.enabled(默认true)
(3)在这几个配置类加载之后再进行加载,AutoServiceRegistrationConfiguration、AutoServiceRegistrationAutoConfiguration、NacosDiscoveryAutoConfiguration
这里我们暂时不管这几个类是的具体作用。
2、当前配置类创建了一个名为NacosServiceRegistry的Bean,该Bean使用执行注册逻辑(下文分析)
3、接着又创建了一个名为NacosRegistration的Bean,该Bean的主要作用是配置一些Nacos相关的信息,例如心跳周期、多久收不到心跳剔除服务等。
4、最后创建了一个名为NacosAutoServiceRegistration的Bean,顾名思义这个Bean的作用是用来实现自动注册的。

2、自动注册源码分析

1、流程简单分析

上面的简单分析我们清楚了实现自动注册的类是NacosAutoServiceRegistration,而执行注册逻辑的Bean是NacosServiceRegistry。那么我们对NacosAutoServiceRegistration做一下源码分析:(我们除去一些非核心代码)

public class NacosAutoServiceRegistration
		extends AbstractAutoServiceRegistration<Registration> {
	@Override
	protected NacosRegistration getManagementRegistration() {
		return null;
	}

	@Override
	protected void register() {
		if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
			log.debug("Registration disabled.");
			return;
		}
		if (this.registration.getPort() < 0) {
			this.registration.setPort(getPort().get());
		}
		super.register();
	}
}
可以看到这个方法非常简单,只是做了一些基本的校验,校验通过就调用调用super.register()方法来进行注册,点开这个Register方法你会发现其实就是上一小结说的创建的第二个Bean也就是**NacosServiceRegistry**,中的Register方法;由于服务注册到Nacos中的代码不是很难,**可以简单的理解为通过HttpClient发送了一个POST请求,然后就注册上了。**

2、如何自动注册的呢?

我们现在知道了注册的方法,但是目前还未解决的问题是,如何自动注册的?是谁调用了注册方法?带这个问题我们继续从源码中寻找答案。回到源码中NacosAutoServiceRegistration继承了一个抽象类AbstractAutoServiceRegistration;
Nacos学习笔记(三):服务是如何自动注册的_第2张图片
进入AbstractAutoServiceRegistration类中,可以看到其中有一个start方法里调用了register方法。
Nacos学习笔记(三):服务是如何自动注册的_第3张图片
那么现在的问题变成了,是谁调用了start方法呢?通过Idea可以很轻松的找到start方法的调用方。最终我们在NacosDiscoveryProperties中找到了答案。
Nacos学习笔记(三):服务是如何自动注册的_第4张图片
这里附上代码(因为有@PostConstruct,所以该方法会在spring容器初始化的时候被执行)

	@PostConstruct
	public void init() throws Exception {

		metadata.put(PreservedMetadataKeys.REGISTER_SOURCE, "SPRING_CLOUD");
		if (secure) {
			metadata.put("secure", "true");
		}

		serverAddr = Objects.toString(serverAddr, "");
		if (serverAddr.endsWith("/")) {
			serverAddr = serverAddr.substring(0, serverAddr.length() - 1);
		}
		endpoint = Objects.toString(endpoint, "");
		namespace = Objects.toString(namespace, "");
		logName = Objects.toString(logName, "");

		if (StringUtils.isEmpty(ip)) {
			// traversing network interfaces if didn't specify a interface
			if (StringUtils.isEmpty(networkInterface)) {
				ip = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
			}
			else {
				NetworkInterface netInterface = NetworkInterface
						.getByName(networkInterface);
				if (null == netInterface) {
					throw new IllegalArgumentException(
							"no such interface " + networkInterface);
				}

				Enumeration<InetAddress> inetAddress = netInterface.getInetAddresses();
				while (inetAddress.hasMoreElements()) {
					InetAddress currentAddress = inetAddress.nextElement();
					if (currentAddress instanceof Inet4Address
							&& !currentAddress.isLoopbackAddress()) {
						ip = currentAddress.getHostAddress();
						break;
					}
				}

				if (StringUtils.isEmpty(ip)) {
					throw new RuntimeException("cannot find available ip from"
							+ " network interface " + networkInterface);
				}

			}
		}

		this.overrideFromEnv(environment);

		nacosAutoServiceRegistrationOptional.ifPresent(nacosAutoServiceRegistration -> {
			if (nacosServiceManager.isNacosDiscoveryInfoChanged(this)) {
				nacosAutoServiceRegistration.stop();
				nacosServiceManager.reBuildNacosService(getNacosProperties());
				nacosAutoServiceRegistration.start();
			}
		});
	}

三、总结

通过上文的分析,想必你一定有一点被绕晕了,毕竟这么多类,这么多流程。下面我们做一个总结;
1、Nacos自动注册依赖的是NacosServiceRegistryAutoConfiguration这个类。
2、NacosServiceRegistryAutoConfiguration中定义了3个Bean,分别是NacosServiceRegistry、NacosRegistration、NacosAutoServiceRegistration;这三个类的作用分别是
(1)执行具体的注册逻辑即封装数据,发送注册(POST请求)请求到Nacos。
(2)配置一些注册相关的信息,例如心跳周期、服务删除时间等等
(3)定义了自动注册的方法
3、调用自动注册方法的是**NacosDiscoveryProperties类,**该类中的init方法调用了自动注册的方法从而实现了自动注册。
至此我们对服务自动注册应该有一个相对清晰的理解,接下来我们还会继续探究Nacos源码的其他部分,希望对你有所帮助。

四、未完待续

你可能感兴趣的:(从0开始学Nacos,学习,java,spring,boot)