nacos原理--nacos注册原理分析
1. nacos使用
引入pom文件
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>${官方版本号}</version>
</dependency>
在启动类上添加@EnableDiscoveryClient
@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudConfigClientApplication.class, args);
}
}
并添加配置文件
spring.cloud.nacos.discovery.server-addr=http://localhost:8848
2. nacos注册原理
查看spring-cloud-starter-alibaba-nacos-discovery包中spring.factories类能够看到如下源码:
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
@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程序初始化完成后调用:
// 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方法
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发送客户端。如果是临时节点,需要通过心跳的方式维持,而心跳式通过定时任务的方式间隔的发送来保持。

浙公网安备 33010602011771号