项目集成
以springboot和nacos的集成为例。
sb项目中添加nacos-discovery依赖:
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-discovery-spring-boot-starter</artifactId>
<version>0.2.10</version>
</dependency>
nacos:
discovery:
server-addr: http://localhost:8848
namespace: public
username: nacos
password: nacos
auto-register: true
register:
service-name: sb-provider
healthy: true
要注意的属性:
- auto-register: 这个配置默认是false,也就是默认不会将此实例注册到nacos server
- register.service-name :当前实例的service name,不能为空,否则项目启动完之后,注册到nacos server时会报错。这是nacos-client的内部的一个校验。
解析
starter
找到我们集成nacos client使用的jar包:nacos-discovery-spring-boot-starter

再看 nacos-discovery-spring-boot-autoconfigure , 根据命名就可以看出来,这是nacos装配的配置就在这里了

直接看 spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.boot.nacos.discovery.autoconfigure.NacosDiscoveryAutoConfiguration
看到org.springframework.boot.autoconfigure.EnableAutoConfiguration其实就懂关键的装配代码在哪里了,那就直接看NacosDiscoveryAutoConfiguration

代码很简单,从@Bean就可以看出自动注册是通过 new NacosDiscoveryAutoRegister() 实现的。
还是那一套,通过SpringEvent监听 WebServerInitializedEvent事件来实现。

前边几个校验逻辑很简单,那关键的就是 namingService.registerInstance 这里做实例注册的事情了。
NamingService
@Override
public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
NamingUtils.checkInstanceIsLegal(instance);
clientProxy.registerService(serviceName, groupName, instance);
}
NamingUtils.checkInstanceIsLegal(instance); 这里是业务校验,校验了以下两个设置是否有误:
- heart beat timeout must > heart beat interval
- ip delete timeout must > heart beat interval
ps:其实就是校验设置的超时时间是否符合要求,要求就是要大于默认的心跳周期。很合理😎
那么重头戏就是clientProxy.registerService(serviceName, groupName, instance)这个方法了。
clientProxy是一个接口,封装了很多service相关的操作。嗯,合理👍
那么具体来看registerService是怎么实现的
@Override
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
getExecuteClientProxy(instance).registerService(serviceName, groupName, instance);
}
private NamingClientProxy getExecuteClientProxy(Instance instance) {
return instance.isEphemeral() ? grpcClientProxy : httpClientProxy;
}
为什么根据是否是临时实例而选择不同的clientProxy?
it’s a question . 👀❓
先不管了,接着看
@Override
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance {}", namespaceId, serviceName,
instance);
redoService.cacheInstanceForRedo(serviceName, groupName, instance);
doRegisterService(serviceName, groupName, instance);
}
redoService.cacheInstanceForRedo 做的事情就是将本实例做个缓存。
private final ConcurrentMap<String, InstanceRedoData> registeredInstances = new ConcurrentHashMap<>();
public void cacheInstanceForRedo(String serviceName, String groupName, Instance instance) {
String key = NamingUtils.getGroupedName(serviceName, groupName);
InstanceRedoData redoData = InstanceRedoData.build(serviceName, groupName, instance);
//registeredInstances是个map
synchronized (registeredInstances) {
registeredInstances.put(key, redoData);
}
}

InstanceRedoData有个属性叫registered,语义是: 是否注册。
可以看到第一次放到缓存的时候这个属性是false
接着看doRegisterService
public void doRegisterService(String serviceName, String groupName, Instance instance) throws NacosException {
InstanceRequest request = new InstanceRequest(namespaceId, serviceName, groupName,
NamingRemoteConstants.REGISTER_INSTANCE, instance);
requestToServer(request, Response.class);
redoService.instanceRegistered(serviceName, groupName);
}
requestToServer内部是调用方法去server注册实例,就不研究了。
public void instanceRegistered(String serviceName, String groupName) {
String key = NamingUtils.getGroupedName(serviceName, groupName);
synchronized (registeredInstances) {
InstanceRedoData redoData = registeredInstances.get(key);
if (null != redoData) {
redoData.setRegistered(true);
}
}
}
instanceRegistered就是将刚才缓存的实例registered字段修改为true,代表此实例已在server端注册成功。
下一篇研究下server是怎么处理client的service注册请求的
本文详细介绍了SpringBoot项目中如何集成Nacos,并深入解析了Nacos服务发现的实例注册过程,包括配置项、自动注册逻辑、服务注册的关键代码以及客户端与服务端的交互细节。
1853





