nacos原理--nacos注册原理分析
1. nacos使用
引入pom文件
1 2 3 4 5 | <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>${官方版本号}</version> </dependency> |
在启动类上添加@EnableDiscoveryClient
1 2 3 4 5 6 7 8 | @SpringBootApplication @EnableDiscoveryClient public class SpringCloudConfigClientApplication { public static void main(String[] args) { SpringApplication.run(SpringCloudConfigClientApplication. class , args); } } |
并添加配置文件
1 | spring.cloud.nacos.discovery.server-addr=http: //localhost:8848 |
2. nacos注册原理
查看spring-cloud-starter-alibaba-nacos-discovery包中spring.factories类能够看到如下源码:
1 2 3 4 5 6 7 8 9 10 | 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 org.springframework.cloud.bootstrap.BootstrapConfiguration=\ com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration |
其中关键类:NacosServiceRegistryAutoConfiguration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @Bean public NacosServiceRegistry nacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) { return new NacosServiceRegistry(nacosDiscoveryProperties); } @Bean @ConditionalOnBean (AutoServiceRegistrationProperties. class ) public NacosRegistration nacosRegistration(NacosDiscoveryProperties nacosDiscoveryProperties,ApplicationContext context) { return new NacosRegistration(nacosDiscoveryProperties, context); } @Bean @ConditionalOnBean (AutoServiceRegistrationProperties. class ) public NacosAutoServiceRegistration nacosAutoServiceRegistration( NacosServiceRegistry registry,AutoServiceRegistrationProperties autoServiceRegistrationProperties,NacosRegistration registration) { return new NacosAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration); } |
NacosServiceRegistry和NacosRegistration都将作为参数注册到NacosAutoServiceRegistration,那么NacosAutoServiceRegistration是个核心类,同时能够看到继承的接口AbstractAutoServiceRegistration也继承了ApplicationListener<WebServerInitializedEvent>,那么就是当Web程序初始化完成后调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | // web程序初始化完成后发送消息,本类监听到事件后执行 public void onApplicationEvent(WebServerInitializedEvent event) { this .bind(event); } public void bind(WebServerInitializedEvent event) { ApplicationContext context = event.getApplicationContext(); if (!(context instanceof ConfigurableWebServerApplicationContext) || ! "management" .equals(((ConfigurableWebServerApplicationContext)context).getServerNamespace())) { this .port.compareAndSet( 0 , event.getWebServer().getPort()); this .start(); } } public void start() { if (! this .isEnabled()) { //... } else { // 用于是否已经注册了 if (! this .running.get()) { this .context.publishEvent( new InstancePreRegisteredEvent( this , this .getRegistration())); // 关键方法,即本方法就是将服务注册到nacos中 this .register(); if ( this .shouldRegisterManagement()) { this .registerManagement(); } this .context.publishEvent( new InstanceRegisteredEvent( this , this .getConfiguration())); this .running.compareAndSet( false , true ); } } } // 此处就调用NacosServiceRegistry中register方法 protected void register() { this .serviceRegistry.register( this .getRegistration()); } |
接下啦是NacosServiceRegistry类register方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | public void register(Registration registration) { // 服务ID为空直接退出 if (StringUtils.isEmpty(registration.getServiceId())) { return ; } String serviceId = registration.getServiceId(); String group = nacosDiscoveryProperties.getGroup(); // 生成Instance Instance instance = getNacosInstanceFromRegistration(registration); try { // 调用http请求注册 namingService.registerInstance(serviceId, group, instance); } } public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException { if (instance.isEphemeral()) { // 如果是临时实例,需要通过心跳的方式保持 BeatInfo beatInfo = new BeatInfo(); beatInfo.setServiceName(NamingUtils.getGroupedName(serviceName, groupName)); beatInfo.setIp(instance.getIp()); beatInfo.setPort(instance.getPort()); beatInfo.setCluster(instance.getClusterName()); beatInfo.setWeight(instance.getWeight()); beatInfo.setMetadata(instance.getMetadata()); beatInfo.setScheduled( false ); beatInfo.setPeriod(instance.getInstanceHeartBeatInterval()); // 定时任务,每隔一段时间发送短信 this .beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), beatInfo); } // 注册 this .serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance); } // 发送心跳 public void addBeatInfo(String serviceName, BeatInfo beatInfo) { // ...省略 this .dom2Beat.put(key, beatInfo); // 定时任务 this .executorService.schedule( new BeatReactor.BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit.MILLISECONDS); MetricsMonitor.getDom2BeatSizeMonitor().set(( double ) this .dom2Beat.size()); } // 参数拼接调用http请求 public void registerService(String serviceName, String groupName, Instance instance) throws NacosException { LogUtils.NAMING_LOGGER.info( "[REGISTER-SERVICE] {} registering service {} with instance: {}" , new Object[]{ this .namespaceId, serviceName, instance}); Map<String, String> params = new HashMap( 9 ); params.put( "namespaceId" , this .namespaceId); params.put( "serviceName" , serviceName); params.put( "groupName" , groupName); params.put( "clusterName" , 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" , JSON.toJSONString(instance.getMetadata())); this .reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, "POST" ); } |
总结:nacos客户端注册原理简单,通过找到Spring注解的源码,并顺着往下读,基本能够看到Nacos通过http的方式将生产的Instance发送客户端。如果是临时节点,需要通过心跳的方式维持,而心跳式通过定时任务的方式间隔的发送来保持。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构