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
注册中心的简单实例,之后我们的各种演示都会基于这个基础上进行