Nacos 的工作流程剖析
image-20250719124926528
Nacos 服务注册部分
有这么一个包,spring-cloud-commons
image-20250719124212246
在这里,你会看到一个熟悉的包,loadbalancer,这就是我们之前深度分析的负载均衡的包,Nacos的负载均衡先不讲,在这个包下面,有个
serviceregistry包,这个包的作用就是服务注册相关内容的包
image-20250719125222356
其中,ServiceRegistry
包是关注与服务注册相关的核心接口,这个ServiceRegistry接口是Spring
Cloud提供的服务注册的标准,集成到SpringCloud中实现服务注册的组件,都需要实现这个接口。 看一下它的代码
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 package org.springframework.cloud.client.serviceregistry;public interface ServiceRegistry <R extends Registration > { void register (R registration) ; void deregister (R registration) ; void close () ; void setStatus (R registration, String status) ; <T> T getStatus (R registration) ; }
那么,Erueka有着它对应的实现类,Nacos也有,对于Nacos而言,该接口的实现类是NacosServiceRegistry,它在com.alibaba.cloud.nacos.registry;包下,这个包就是
Nacos 的服务注册的具体实现
image-20250719135343514
其中的成员变量,nacosDiscoveryProperties是NacosDiscoveryProperties类型,用于获取
Nacos
服务发现相关的配置信息,而nacosServiceManager是NacosServiceManager类型,负责管理
Nacos
的命名服务(NamingService),包括获取、创建和关闭等操作。
核心方法register(Registration registration)
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 public void register (Registration registration) { if (StringUtils.isEmpty(registration.getServiceId())) { log.warn("No service to register for nacos client..." ); } else { NamingService namingService = this .namingService(); String serviceId = registration.getServiceId(); String group = this .nacosDiscoveryProperties.getGroup(); Instance instance = this .getNacosInstanceFromRegistration(registration); try { namingService.registerInstance(serviceId, group, instance); log.info("nacos registry, {} {} {}:{} register finished" , new Object []{group, serviceId, instance.getIp(), instance.getPort()}); } catch (Exception e) { if (this .nacosDiscoveryProperties.isFailFast()) { log.error("nacos registry, {} register failed...{}," , new Object []{serviceId, registration.toString(), e}); ReflectionUtils.rethrowRuntimeException(e); } else { log.warn("Failfast is false. {} register failed...{}," , new Object []{serviceId, registration.toString(), e}); } } } }
而挑出来这个setStatus(Registration registration, String status)讲一下,这是
Nacos 设置服务状态的核心
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public void setStatus (Registration registration, String status) { if (!"UP" .equalsIgnoreCase(status) && !"DOWN" .equalsIgnoreCase(status)) { log.warn("can't support status {},please choose UP or DOWN" , status); } else { String serviceId = registration.getServiceId(); Instance instance = this .getNacosInstanceFromRegistration(registration); if ("DOWN" .equalsIgnoreCase(status)) { instance.setEnabled(false ); } else { instance.setEnabled(true ); } try { Properties nacosProperties = this .nacosDiscoveryProperties.getNacosProperties(); this .nacosServiceManager.getNamingMaintainService(nacosProperties).updateInstance(serviceId, this .nacosDiscoveryProperties.getGroup(), instance); } catch (Exception e) { throw new RuntimeException ("update nacos instance status fail" , e); } } }
AutoServiceRegistrationAutoConfiguration这个类,顾名思义是服务注册相关的配置类 。这个配置类是
Spring Cloud
服务注册功能的核心配置,它实现了服务的自动注册和注销功能,使应用能够自动向服务注册中心注册自己,并在应用关闭时自动注销。
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 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 @Configuration(proxyBeanMethods = false) @Import({AutoServiceRegistrationConfiguration.class}) @ConditionalOnProperty( value = {"spring.cloud.service-registry.auto-registration.enabled"}, matchIfMissing = true ) @EnableConfigurationProperties({AutoServiceRegistrationProperties.class}) public class AutoServiceRegistrationAutoConfiguration implements InitializingBean { @Autowired(required = false) private AutoServiceRegistration autoServiceRegistration; @Autowired private AutoServiceRegistrationProperties properties; @Override public void afterPropertiesSet () { if (this .autoServiceRegistration == null && this .properties.isFailFast()) { throw new IllegalStateException ("Auto Service Registration has been requested, but there is no AutoServiceRegistration bean" ); } } @Bean @ConditionalOnBean(AutoServiceRegistrationProperties.class) public AutoServiceRegistration autoServiceRegistration ( ServiceRegistry<?> serviceRegistry, Registration registration, AutoServiceRegistrationProperties autoServiceRegistrationProperties, InetUtils inetUtils) { return new AutoServiceRegistrationAdapter (serviceRegistry, registration, autoServiceRegistrationProperties, inetUtils); } private static class AutoServiceRegistrationAdapter implements AutoServiceRegistration { private final ServiceRegistry<?> serviceRegistry; private final Registration registration; private final AutoServiceRegistrationProperties properties; private final InetUtils inetUtils; public AutoServiceRegistrationAdapter (ServiceRegistry<?> serviceRegistry, Registration registration, AutoServiceRegistrationProperties properties, InetUtils inetUtils) { this .serviceRegistry = serviceRegistry; this .registration = registration; this .properties = properties; this .inetUtils = inetUtils; } @Override public void start () { if (!this .properties.isEnabled()) { return ; } this .serviceRegistry.register(this .registration); if (log.isInfoEnabled()) { log.info("Auto service registration enabled. Registering service with name: {}" , this .registration.getServiceId()); } } @Override public void stop () { if (!this .properties.isEnabled()) { return ; } this .serviceRegistry.deregister(this .registration); if (log.isInfoEnabled()) { log.info("Auto service registration disabled. Deregistering service with name: {}" , this .registration.getServiceId()); } } } private static final Logger log = LoggerFactory.getLogger(AutoServiceRegistrationAutoConfiguration.class); }
NacosAutoServiceRegistration继承了这个类,而NacosAutoServiceRegistration这个的继承实现关系如下
image-20250719140057343
再来看看看这个抽象类,AbstractAutoServiceRegistration,这个类长的一批,但是它实现了以下接口:
1 public abstract class AbstractAutoServiceRegistration <R extends Registration > implements AutoServiceRegistration , ApplicationContextAware, ApplicationListener<WebServerInitializedEvent> {
AutoServiceRegistration:服务自动注册接口
ApplicationContextAware:用于获取 Spring
应用上下文
ApplicationListener<WebServerInitializedEvent>:监听
Web 服务器初始化事件
而R extends Registration
表示参数必须是Registration接口的实现类,这使得该类可以处理不同类型的服务注册信息,所以说,这个类是负责服务的自动注册功能。
NacosAutoServiceRegistration监听WebServerInitializedEvent事件。而在也就是WebServer初始化完成后 ,调用onApplicationEvent(),也就是事件被监听到,然后从事件中获取上下文对象,检查上下文是否是ConfigurableWebServerApplicationContext类型,之后调用start()方法开始服务注册流程
再继续作为抽象类的子类实现NacosAutoServiceRegistration,监听到Web服务启动后,
开始执行super.register()方法。
1 2 3 4 5 6 7 public void onApplicationEvent (WebServerInitializedEvent event) { ApplicationContext context = event.getApplicationContext(); if (!(context instanceof ConfigurableWebServerApplicationContext) || !"management" .equals(((ConfigurableWebServerApplicationContext)context).getServerNamespace())) { this .port.compareAndSet(0 , event.getWebServer().getPort()); this .start(); } }
image-20250719141045941
继续,来看看register()方法,对于register()方法,主要调用的是Nacos
Client
SDK中的NamingService下的registerInstance()方法完成服务的注册 。
1 2 3 protected void register () { this .serviceRegistry.register(this .getRegistration()); }
可以看到,AbstractAutoServiceRegistration抽象类的方法调度的是serviceRegistry的服务注册标准组件,而也就是实际上调度的是NacosServiceRegistry,这个方法最终会调用
NacosServiceRegistry的register()方法(别忘了NacosServiceRegistry实现了Spring的一个服务注册标准接口)。在上面,我们仔细分析了这个方法。
对于register()方法,核心主要调用的是Nacos Client
SDK中的NamingService下的registerInstance()方法完成服务的注册 。
1 2 3 4 try { namingService.registerInstance(serviceId, group, instance); log.info("nacos registry, {} {} {}:{} register finished" , new Object []{group, serviceId, instance.getIp(), instance.getPort()});
可以看到,其中三个registerInstance()方法都是对配置规则和默认配置的选择执行
image-20250719142312477
NamingService
这个接口在前面我们说过了,它定义了与服务注册和发现相关的核心操作,是
Nacos 客户端进行服务注册与发现功能的关键抽象。
也就是说,AbstractAutoServiceRegistration这个抽象类是
Spring Cloud 服务自动注册的核心抽象类 ,而在 Nacos
服务注册流程中扮演调度中心的角色。它承上启下,连接 Spring Boot
的启动生命周期与 Nacos
的服务注册逻辑,NacosAutoServiceRegistration继承此类,实现抽象方法(如getRegistration()返回
Nacos
的服务实例对象)。而且通过ServiceRegistry接口依赖NacosServiceRegistry,将注册逻辑委托给
Nacos 客户端。
Nacos心跳检测机制
继续我们的过程,在上述AbstractAutoServiceRegistration抽象方法进行反复调用,调用到NacosServiceRegistry下的
register方法中,我们继续深入,其实还会发现这个创建实例的方法
1 Instance instance = this .getNacosInstanceFromRegistration(registration);
这个方法其实也不难,就是 set
各种内容,完成实例的创建,但是其中有这么一条
1 instance.setEphemeral(this .nacosDiscoveryProperties.isEphemeral());
这个方法返回的是该实例是否是临时实例。还记得之前所说的心跳机制吗,临时实例会使用心跳机制,而非临时实例则不会。我们继续找,发现这个配置类nacosDiscoveryProperties
image-20250719184454100
这个配置类记录了 Nacos
大部分服务发现的详细配置内容,且标注了@ConfigurationProperties("spring.cloud.nacos.discovery")注解,意味着都可以在配置文件中进行详细的配置
在 NacosDiscoveryProperties
类中,有几个与心跳机制相关的属性:
image-20250719184752499
heartBeatInterval:心跳间隔,即客户端向 Nacos
服务器发送心跳的时间间隔。
heartBeatTimeout:心跳超时时间,即 Nacos
服务器等待客户端心跳的最长时间。如果在这个时间内没有收到客户端的心跳,Nacos
服务器会将该实例标记为不健康。
ipDeleteTimeout:IP
删除超时时间,即当实例被标记为不健康后,Nacos
服务器等待多久才会将该实例从服务列表中删除。
在 NacosDiscoveryProperties 类中,有一个
ephemeral 属性:这个属性表示该服务实例是否是临时实例。如果
ephemeral 设置为
true,则该实例是临时实例,Nacos
客户端会定期发送心跳包;如果设置为
false,则该实例是非临时实例,Nacos
客户端不会发送心跳包,而是依赖于其他机制(如健康检查)来判断实例的健康状态。
image-20250719185006738
我们进入到其中的NacosDiscoveryHeartBeatConfiguration类中,可以发现,这是nacos心跳机制的详细配置类,专门用于初始化
Nacos
服务发现的心跳发布器 ,他会在在满足特定条件时,创建并注册一个心跳发布器实例,负责向
Nacos 服务器发送心跳信号,以维持服务实例的健康状态。
image-20250719185122690
而其中,该配置类通过 @Bean 方法定义了
NacosDiscoveryHeartBeatPublisher
实例,它是实际执行心跳逻辑的组件,它会根据
NacosDiscoveryProperties
中的配置(如心跳间隔、超时时间等),定期向 Nacos
服务器发送心跳请求@ConditionalOnMissingBean
确保全局只存在一个心跳发布器实例,避免重复发送心跳。
内部静态类 NacosDiscoveryHeartBeatCondition
定义了心跳机制生效的条件(通过 @Conditional
注解控制),满足以下任一条件时,心跳发布器才会被创建:
条件
1 :网关服务发现启用(spring.cloud.gateway.discovery.locator.enabled=true)
当使用 Spring Cloud Gateway
并开启服务发现时,需要心跳机制维护实例健康状态。
条件 2 :Spring Boot Admin 监控启用 当集成 Spring
Boot Admin 时,需要通过心跳机制实时 Admin 感知实例存活状态。
条件 3 :显式开启 Nacos
心跳(spring.cloud.nacos.discovery.heart-beat.enabled=true)
直接通过配置强制启用心跳机制。
进入到NacosDiscoveryHeartBeatPublisher
类中,NacosDiscoveryHeartBeatPublisher 构造时依赖
NacosDiscoveryProperties,这意味着它会读取我们之前提到的心跳相关配置
该类实现了两个关键接口:
ApplicationEventPublisherAware:用于获取 Spring
的事件发布器,通过事件机制发送心跳信号。
SmartLifecycle:控制心跳任务的启动、停止等生命周期管理。
1 public class NacosDiscoveryHeartBeatPublisher implements ApplicationEventPublisherAware , SmartLifecycle
心跳机制的核心实现,启动心跳任务(start() 方法)
1 2 3 4 5 6 7 8 9 10 11 public void start () { if (this .running.compareAndSet(false , true )) { log.info("Start nacos heartBeat task scheduler." ); this .heartBeatFuture = this .taskScheduler.scheduleWithFixedDelay( this ::publishHeartBeat, Duration.ofMillis(this .nacosDiscoveryProperties.getWatchDelay()) ); } }
通过 compareAndSet 保证线程安全,避免重复启动。
使用 scheduleWithFixedDelay 定时执行
publishHeartBeat 方法,间隔时间由
nacosDiscoveryProperties.getWatchDelay() 决定(默认 30
秒,可通过配置 spring.cloud.nacos.discovery.watch-delay
修改)。
发布心跳事件(publishHeartBeat() 方法)
1 2 3 4 5 6 public void publishHeartBeat () { HeartbeatEvent event = new HeartbeatEvent (this , this .nacosHeartBeatIndex.getAndIncrement()); this .publisher.publishEvent(event); }
NacosDiscoveryHeartBeatPublisher 内部会通过 Nacos 客户端
SDK 与服务器通信,这就联系到我们之前讲的心跳机制的原理内容了。该事件通过
Spring 的事件发布器 publisher 发布事件,后续会由 Nacos
客户端的监听器捕获并处理(实际向 Nacos 服务器发送心跳请求)。
就这么不断进入,你会发现回到了 Spring Boot
的事件管理机制相关的内容了
image-20250719185717993
Nacos 的服务发现机制
先说一点要清楚,Nacos服务的发现发生在什么时候,在 Spring Cloud
Alibaba 整合 Nacos 的场景中,Nacos 服务发现主要发生在以下几个阶段:
配置加载:应用启动时,Spring Boot
会加载配置文件(如application.yml)中关于 Nacos
的配置信息,这些配置信息用于初始化 Nacos 客户端
Nacos
客户端初始化:NacosDiscoveryAutoConfiguration等自动配置类会发挥作用,创建并初始化NacosDiscoveryProperties(封装
Nacos 发现相关配置属性)、NamingService(Nacos
提供的用于服务注册与发现的核心接口) 等相关组件。
服务注册与发现触发 :在初始化过程中,会判断当前应用是否需要注册到
Nacos(通过spring.cloud.nacos.discovery.register-enabled配置,默认开启)。如果需要注册,会将自身服务信息(如服务名、IP、端口等)注册到
Nacos 服务器。
服务状态变更监听 或者手动刷新:Nacos
客户端会持续监听 Nacos
服务器上服务实例状态的变化,如某个服务实例的启动、停止、健康状态改变等。一旦有变化,客户端会及时更新本地的服务列表缓存。
服务调用阶段:当一个服务需要调用另一个服务时
负载均衡前的发现
手动编写业务从一个服务需要调用另一个服务的业务的时候
Nacos在进行服务发现的时候,回到老地方,spring-cloud-starter-alibaba-nacos-discovery,其中有这么一个包
image-20250719190523088
读源码我习惯从自动配置类阅读,能够了解前置条件,并且找到很多你想要的东西,所以我们来到NacosDiscoveryAutoConfiguration类
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 @Configuration( proxyBeanMethods = false // 关闭@Configuration类的Bean方法代理,提高性能 ) @ConditionalOnDiscoveryEnabled @ConditionalOnNacosDiscoveryEnabled public class NacosDiscoveryAutoConfiguration { @Bean @ConditionalOnMissingBean public NacosDiscoveryProperties nacosProperties () { return new NacosDiscoveryProperties (); } @Bean @ConditionalOnMissingBean public NacosServiceDiscovery nacosServiceDiscovery (NacosDiscoveryProperties discoveryProperties, NacosServiceManager nacosServiceManager) { return new NacosServiceDiscovery (discoveryProperties, nacosServiceManager); } }
接下来,我们阅读 NacosServiceManager的 Nacos
服务管理器看看,这个类是 Nacos
服务发现功能的核心管理类,负责创建、管理和销毁 Nacos
客户端实例(NamingService 和
NamingMaintainService)。它通过单例模式和延迟初始化确保
Nacos 客户端的高效使用,同时处理配置变更和资源释放
来看看它引入了什么属性
1 2 3 4 5 6 private NacosDiscoveryProperties nacosDiscoveryProperties;private volatile NamingService namingService;private volatile NamingMaintainService namingMaintainService;
NamingService 上面我们也说了,是 Nacos
服务发现的核心接口,提供服务注册、发现、心跳检测等功能。NacosServiceManager
通过延迟初始化 和双重检查锁 确保其单例性,避免重复创建客户端实例。
1 2 3 4 5 6 7 8 public NamingService getNamingService () { if (Objects.isNull(this .namingService)) { this .buildNamingService(this .nacosDiscoveryProperties.getNacosProperties()); } return this .namingService; }
接下来就是构建 NamingService方法,然后通过 NacosFactory
创建底层的服务
image-20250720121834238
当首次调用 getNamingService() 时,会从
nacosDiscoveryProperties 中获取配置(如 Nacos 服务端地址
server-addr),通过 NacosFactory
创建客户端实例,并通过双重检查锁确保全局唯一。后续调用直接返回已创建的实例。
那么这里配置中心是如何体现出来的,可以看到接下来有个方法isNacosDiscoveryInfoChanged,就是用来做配置变更检测,Nacos
大部分业务类中都有这个配置检测变更的方法
1 2 3 4 5 public boolean isNacosDiscoveryInfoChanged (NacosDiscoveryProperties currentCache) { return !Objects.isNull(this .nacosDiscoveryProperties) && !this .nacosDiscoveryProperties.equals(currentCache); }
若返回 true,表示配置已变更,上层逻辑会调用
nacosServiceShutDown() 销毁旧实例,再通过
getNamingService() 创建新实例。
最后剩下一个资源释放
来继续看NacosServiceDiscovery类,这就是Nacos服务发现功能的核心类了,它封装了与
Nacos 服务端交互的细节,向上层提供标准化的服务发现接口
image-20250720122317600
一上来就是两个属性,这俩属性上面也都说过了,Nacos 服务发现配置属性 和
Nacos
服务管理器,然后同构造函数注入,接下来就是getInstances
方法,这是服务实例的发现方法,是服务发现的核心
1 2 3 4 5 6 7 8 9 10 11 public List<ServiceInstance> getInstances (String serviceId) throws NacosException { String group = this .discoveryProperties.getGroup(); List<Instance> instances = this .namingService().selectInstances(serviceId, group, true ); return hostToServiceInstanceList(instances, serviceId); }
通过 namingService() 方法获取 NamingService
实例(复用之前讲解的 NacosServiceManager 管理的客户端)
1 2 3 4 private NamingService namingService () { return this .nacosServiceManager.getNamingService(); }
Nacos 原生返回 Instance 类型,需要转换为 Spring Cloud
标准的 ServiceInstance 接口实现,以便上层框架(如 Spring
Cloud LoadBalancer)使用,虽然 Nacos 也有自己的负载均衡:
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 public static List<ServiceInstance> hostToServiceInstanceList (List<Instance> instances, String serviceId) { List<ServiceInstance> result = new ArrayList (instances.size()); for (Instance instance : instances) { ServiceInstance serviceInstance = hostToServiceInstance(instance, serviceId); if (serviceInstance != null ) { result.add(serviceInstance); } } return result; } public static ServiceInstance hostToServiceInstance (Instance instance, String serviceId) { if (instance != null && instance.isEnabled() && instance.isHealthy()) { NacosServiceInstance nacosServiceInstance = new NacosServiceInstance (); nacosServiceInstance.setHost(instance.getIp()); nacosServiceInstance.setPort(instance.getPort()); nacosServiceInstance.setServiceId(serviceId); nacosServiceInstance.setInstanceId(instance.getInstanceId()); Map<String, String> metadata = new HashMap (); metadata.put("nacos.instanceId" , instance.getInstanceId()); metadata.put("nacos.weight" , "" + instance.getWeight()); metadata.put("nacos.healthy" , "" + instance.isHealthy()); metadata.put("nacos.cluster" , "" + instance.getClusterName()); metadata.put("nacos.ephemeral" , String.valueOf(instance.isEphemeral())); if (instance.getMetadata() != null ) { metadata.putAll(instance.getMetadata()); } nacosServiceInstance.setMetadata(metadata); if (metadata.containsKey("secure" )) { boolean secure = Boolean.parseBoolean((String)metadata.get("secure" )); nacosServiceInstance.setSecure(secure); } return nacosServiceInstance; } else { return null ; } }
可以看到
仅保留 enabled(启用)且
healthy(健康)的实例,保证服务调用的可用性
元数据(metadata)同时包含 Nacos
系统属性(如权重、集群)和用户自定义属性,兼顾框架需求和业务扩展
适配 Spring Cloud 标准接口,使 Nacos 可以无缝集成到 Spring Cloud
生态中
然后还有一个就是获取服务列表,getServices 方法用于获取
Nacos 服务端注册的所有服务名称,流程如下:
1 2 3 4 5 6 7 8 9 10 11 public List<String> getServices () throws NacosException { String group = this .discoveryProperties.getGroup(); ListView<String> services = this .namingService().getServicesOfServer(1 , Integer.MAX_VALUE, group); return services.getData(); }
总结一下:
初始化阶段 :
NacosServiceDiscovery 依赖
NacosServiceManager 获取 NamingService
客户端实例
NamingService 通过 NacosFactory
基于配置(NacosDiscoveryProperties)创建,与 Nacos
服务端建立连接
服务发现阶段 :
应用调用 getInstances(String serviceId)
方法,传入目标服务名
方法从配置中获取服务分组,调用
NamingService.selectInstances 向 Nacos 服务端发起查询
Nacos 服务端返回该服务下所有健康实例(Instance
列表)
客户端将 Instance 转换为 Spring Cloud 标准的
ServiceInstance 列表,过滤不健康实例并补充元数据
服务列表查询阶段 :
调用 getServices() 方法时,通过
NamingService.getServicesOfServer 获取所有服务名称
返回结果供控制台或监控系统展示服务注册情况
Nacos
服务注册与订阅的详细使用
nacos 的安装与配置
https://github.com/alibaba/nacos/releases
下载之后进入到bin文件目录,点击startup.cmd,启动项目:
image-20250710143458140
需要以单机模式启动
1 2 startup.cmd -m standalone
需要让你输入一些 nacos
的安全配置,用于不同场景的身份验证和权限控制。分别是生成和验证 JWT
的,用于 Nacos Server 集群间通信时的身份验证和服务身份标识,用于标识当前
Nacos Server 的身份(如集群中的唯一 ID)。
image-20250710143842460
在浏览器地址输入http://localhost:8848/nacos/index.html,默认
nacos 账号密码都是 nacos
至此,nacos已经启动成功,我们可以访问地址:
http://169.254.27.253:8080/index.html
访问nacos的页面。如果需要登录,默认的用户名和密码都是nacos
image-20250710235629676
打开mysql数据库,进行配置,打开Nacos配置]文件
${nacos-server.path}/conf/application.properties
image-20250719183639366
因为 nacos 也是一个 Spring 项目,所以说配置文件肯定也是
application.properties,设置正确的数据库平台为MySQL
1 spring.datasource.platform=mysql
配置数据库连接信息
1 2 3 db.url =jdbc:mysql://你的数据库地址:端口/数据库名?useUnicode=true&characterEncoding=utf8&autoReconnect=true&serverTimezone=UTC db.user =你的数据库用户名 db.password =你的数据库密码
Nacos 在 Spring Cloud
中的服务发现
创建服务提供者模块
nacos-provider,服务提供者是提供接口的微服务,需注册到 Nacos。
添加依赖
1 2 3 4 5 6 7 8 9 10 11 12 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > com.alibaba.cloud</groupId > <artifactId > spring-cloud-starter-alibaba-nacos-discovery</artifactId > </dependency > </dependencies >
配置文件配置,服务消费者和提供者是差不多的,都需要有这个配置,剩下的就是你自己编辑了
1 2 3 4 5 6 7 8 9 spring.application.name =nacos-consumer server.port =8088 spring.cloud.nacos.discovery.server-addr =127.0.0.1:8848 spring.cloud.nacos.discovery.namespace =public
写一个控制器,然后对应的主类也要加上服务发现的注解
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 @RestController @RequestMapping("/provider") public class ProviderController { @Value("${server.port}") private String serverPort; @GetMapping("/hello/{name}") public String hello (@PathVariable String name) { return "你好," + name + "!这是来自端口号为 " + serverPort + " 的服务提供者的响应" ; } @GetMapping("/info") public String info () { return "服务提供者实例,端口号:" + serverPort; } }
创建服务消费者模块 nacos-consumer,服务消费者通过 Nacos 发现 Provider
并调用其接口。依赖是一样的,写一个消费者的控制器,并且把主启动类也加上对应的服务发现注解
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 61 62 63 64 65 66 67 68 69 70 71 72 73 @RestController @RequestMapping("/consumer") public class ConsumerController { @Autowired private RestTemplate restTemplate; @Autowired private DiscoveryClient discoveryClient; private static final String SERVICE_NAME = "nacos-provider" ; @GetMapping("/hello/{name}") public String hello (@PathVariable String name) { return restTemplate.getForObject("http://" + SERVICE_NAME + "/provider/hello/" + name, String.class); } @GetMapping("/provider-info") public String getProviderInfo () { return restTemplate.getForObject("http://" + SERVICE_NAME + "/provider/info" , String.class); } @GetMapping("/discovery") public Object discovery () { List<String> services = discoveryClient.getServices(); StringBuilder sb = new StringBuilder (); sb.append("所有服务: " ).append(services).append("<br/>" ); List<ServiceInstance> instances = discoveryClient.getInstances(SERVICE_NAME); sb.append(SERVICE_NAME).append("服务的实例数量: " ).append(instances.size()).append("<br/>" ); for (ServiceInstance instance : instances) { sb.append("ID: " ).append(instance.getInstanceId()) .append(", Host: " ).append(instance.getHost()) .append(", Port: " ).append(instance.getPort()) .append(", URI: " ).append(instance.getUri()) .append("<br/>" ); } return sb.toString(); } }
别忘了把 Nacos 服务跑起来
image-20250720135020472
先启动服务提供模块,启动后,服务会注册到Nacos,再启动服务消费模块,启动后,服务也会注册到Nacos
image-20250720135335215
image-20250720135359470
image-20250720135444385
image-20250720135550702
可以看到这些模块正常工作,也是可以被正常注册和发现的,然后在这里我们可以进行服务管理、配置管理等操作。
这只是最基本的 Spring Cloud 整合 Nacos
注册中心的简单实例,之后我们的各种演示都会基于这个基础上进行