在上一篇文章中我们学习了Nacos的注册逻辑,笔者在刚接触Nacos的时候就一直有个疑问,为什么我们的微服务(这里以Springboot为例)启动后就会自动注册到Nacos中,我们似乎也没有编写对应的方法去发送注册请求,带着这个疑问我们开始今天的源码学习。
我们找到Nacos相关的依赖,如下图:
可以看到在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的作用是用来实现自动注册的。
上面的简单分析我们清楚了实现自动注册的类是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请求,然后就注册上了。**
我们现在知道了注册的方法,但是目前还未解决的问题是,如何自动注册的?是谁调用了注册方法?带这个问题我们继续从源码中寻找答案。回到源码中NacosAutoServiceRegistration继承了一个抽象类AbstractAutoServiceRegistration;
进入AbstractAutoServiceRegistration类中,可以看到其中有一个start方法里调用了register方法。
那么现在的问题变成了,是谁调用了start方法呢?通过Idea可以很轻松的找到start方法的调用方。最终我们在NacosDiscoveryProperties中找到了答案。
这里附上代码(因为有@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源码的其他部分,希望对你有所帮助。