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发送客户端。如果是临时节点,需要通过心跳的方式维持,而心跳式通过定时任务的方式间隔的发送来保持。