0


【七夕快乐篇】Nacos是如何实现服务注册功能的?

🥇 《Java系核心技术》 《中间件核心技术》
🥇 《微服务核心技术》 《云原生核心技术》

今天是一个美好的日子,祝大家七夕快乐。

很多订阅 《微服务核心技术》 专栏的读者在后台私信说:看Nacos源码时没有思路,面试中还总被问到一些细节。

那么接下的几天里,我们就来逐步分析一下Nacos的源码以及Nacos的核心功能与机制,并着手写一个注册中心,来帮助大家更好的了解分布式中间件。

大家都知道Nacos有两大模块:注册中心和配置中心。

那么Nacos是如何实现注册中心的服务注册的功能呢?我们来一探究竟。

在SpringBoot的基底下,每当我们引入一个新的适配组件,理应看一下该组件下的

/META-INF/spring.factories

文件,上一篇文章《注解@EnableAutoConfiguration的作用以及如何使用》提到,

@SpringBootApplication

会自动加载

/META-INF/spring.factories

文件。

在这里插入图片描述
跟进

NacosServiceRegistryAutoConfiguration

,这个类主要是完成服务注册功能等。

在这里插入图片描述

@Configuration(proxyBeanMethods =false)@EnableConfigurationProperties@ConditionalOnNacosDiscoveryEnabled@ConditionalOnProperty(value ="spring.cloud.service-registry.auto-registration.enabled",
        matchIfMissing =true)@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
        AutoServiceRegistrationAutoConfiguration.class,
        NacosDiscoveryAutoConfiguration.class})publicclassNacosServiceRegistryAutoConfiguration{.........// 服务注册核心bean@Bean@ConditionalOnBean(AutoServiceRegistrationProperties.class)public NacosAutoServiceRegistration nacosAutoServiceRegistration(
            NacosServiceRegistry registry,
            AutoServiceRegistrationProperties autoServiceRegistrationProperties,
            NacosRegistration registration){returnnewNacosAutoServiceRegistration(registry,
                autoServiceRegistrationProperties, registration);}}

跟进

NacosAutoServiceRegistration
publicNacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry,
            AutoServiceRegistrationProperties autoServiceRegistrationProperties,
            NacosRegistration registration){super(serviceRegistry, autoServiceRegistrationProperties);this.registration = registration;}

跟进super【

AbstractAutoServiceRegistration

protectedAbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry,
            AutoServiceRegistrationProperties properties){this.serviceRegistry = serviceRegistry;this.properties = properties;}

在这个类下,有个监听的方法,这个就是服务注册的核心方法了。

@Override@SuppressWarnings("deprecation")publicvoidonApplicationEvent(WebServerInitializedEvent event){// 服务注册的核心方法bind(event);}

那么有监听的事件,就应该有发布的事件,那么事件是在哪里发布的呢?

事件是在

WebServerStartStopLifecycle#start

时发布的

spring容器启动过程中核心方法:

finishRefresh()

,让我们看一看这个方法,算了,我还是专门写一篇吧…移步《Spring源码之finishRefresh()》

SpringApplication#run

启动过程中核心方法:

  1. finishRefresh()
  2. getLifecycleProcessor().onRefresh();
WebServerStartStopLifecycle

(实现SmartLifecycle接口)会发布

ServletWebServerInitializedEvent

事件。

NacosAutoServiceRegistration

onApplicationEvent

方法处理

WebServerInitializedEvent

事件。

@Overridepublicvoidstart(){this.webServer.start();this.running =true;this.applicationContext
                .publishEvent(newServletWebServerInitializedEvent(this.webServer,this.applicationContext));}

知道了它是如何发布的,我们来看一下

AbstractAutoServiceRegistration#bind
@Deprecatedpublicvoidbind(WebServerInitializedEvent event){
        ApplicationContext context = event.getApplicationContext();if(context instanceofConfigurableWebServerApplicationContext){if("management".equals(((ConfigurableWebServerApplicationContext) context).getServerNamespace())){return;}}this.port.compareAndSet(0, event.getWebServer().getPort());// 跟进this.start();}

跟进

this.start()

在这里插入图片描述
跟进

register()

,几经辗转,我们来到

NacosServiceRegistry#register

在这里插入图片描述

跟进

namingService.registerInstance(serviceId, group, instance);

,我们来到

NacosNamingService#registerInstance

,我们重点关注一下

在这里插入图片描述
跟进

NamingProxy#registerService

,组装客户端信息向服务端发送请求。
在这里插入图片描述
由此可见,服务注册的请求是POST,请求路径是

/nacos/v1/ns/instance
publicstatic String webContext ="/nacos";publicstatic String nacosUrlBase = webContext +"/v1/ns";publicstatic String nacosUrlInstance = nacosUrlBase +"/instance";

根据上述结论,我们可以找到服务端对应的API接口:

InstanceController#register

在这里插入图片描述

@CanDistro@PostMapping@Secured(action = ActionTypes.WRITE)public String register(HttpServletRequest request)throws Exception {final String namespaceId = WebUtils
                .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
        NamingUtils.checkServiceNameFormat(serviceName);final Instance instance = HttpRequestInstanceBuilder.newBuilder().setDefaultInstanceEphemeral(switchDomain.isDefaultInstanceEphemeral()).setRequest(request).build();// 跟进getInstanceOperator().registerInstance(namespaceId, serviceName, instance);
        NotifyCenter.publishEvent(newRegisterInstanceTraceEvent(System.currentTimeMillis(),"",false, namespaceId, NamingUtils.getGroupName(serviceName), NamingUtils.getServiceName(serviceName),
                instance.getIp(), instance.getPort()));return"ok";}

跟进

getInstanceOperator().registerInstance(namespaceId, serviceName, instance);
InstanceOperatorServiceImpl#registerInstance
@OverridepublicvoidregisterInstance(String namespaceId, String serviceName, Instance instance)throws NacosException {
        com.alibaba.nacos.naming.core.Instance coreInstance =parseInstance(instance);// 跟进
        serviceManager.registerInstance(namespaceId, serviceName, coreInstance);}

跟进

serviceManager.registerInstance(namespaceId, serviceName, coreInstance);
ServiceManager#registerInstance
publicvoidregisterInstance(String namespaceId, String serviceName, Instance instance)throws NacosException {
        
        NamingUtils.checkInstanceIsLegal(instance);// 跟进createEmptyService(namespaceId, serviceName, instance.isEphemeral());
        
        Service service =getService(namespaceId, serviceName);checkServiceIsNull(service, namespaceId, serviceName);addInstance(namespaceId, serviceName, instance.isEphemeral(), instance);}

跟进

createEmptyService(namespaceId, serviceName, instance.isEphemeral());

最后我们来到

ServiceManager#createServiceIfAbsent
publicvoidcreateServiceIfAbsent(String namespaceId, String serviceName,boolean local, Cluster cluster)throws NacosException {
        Service service =getService(namespaceId, serviceName);//return if service already existsif(service != null){return;}

        Loggers.SRV_LOG.info("creating empty service {}:{}", namespaceId, serviceName);
        service =newService();
        service.setName(serviceName);
        service.setNamespaceId(namespaceId);
        service.setGroupName(NamingUtils.getGroupName(serviceName));// now validate the service. if failed, exception will be thrown
        service.setLastModifiedMillis(System.currentTimeMillis());
        service.recalculateChecksum();if(cluster != null){
            cluster.setService(service);
            service.getClusterMap().put(cluster.getName(), cluster);}
        service.validate();// 跟进putServiceAndInit(service);if(!local){addOrReplaceService(service);}}

跟进

putServiceAndInit(service);
privatevoidputServiceAndInit(Service service)throws NacosException {// 跟进putService(service);
        service =getService(service.getNamespaceId(), service.getName());
        service.init();
        consistencyService
                .listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(),true), service);
        consistencyService
                .listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(),false), service);
        Loggers.SRV_LOG.info("[NEW-SERVICE] {}", service.toJson());}

跟进

putService(service);
publicvoidputService(Service service){if(!serviceMap.containsKey(service.getNamespaceId())){// 将客户端信息存入服务端内存中
            serviceMap.putIfAbsent(service.getNamespaceId(),newConcurrentSkipListMap<>());}
        serviceMap.get(service.getNamespaceId()).putIfAbsent(service.getName(), service);}

再看一眼这个

serviceMap

的定义

/**
 * Map(namespace, Map(group::serviceName, Service)).
 */privatefinal Map<String, Map<String, Service>> serviceMap =newConcurrentHashMap<>();

来吧,总结一下吧,大体分为这么几步:

  1. Spring启动时,先发布Nacos服务注册的事件
  2. 实例化Nacos服务注册的核心类NacosAutoServiceRegistration,并监听事件
  3. 监听到事件之后,对事件进行处理,封装Nacos客户端信息,并发送API请求到Nacos服务端接口
  4. 服务端接收到请求之后,将数据存到初始化的ConcurrentHashMap中,一次完成服务注册

接下来,我们逐步来分析一下Nacos的其他核心机制,并手写一个注册中心,让大家更好的了解这些分布式中间件。

标签: 云原生 微服务

本文转载自: https://blog.csdn.net/CSDN_SAVIOR/article/details/126073428
版权归原作者 步尔斯特 所有, 如有侵权,请联系我们删除。

“【七夕快乐篇】Nacos是如何实现服务注册功能的?”的评论:

还没有评论