乐趣区

关于spring:springcloudalibabanacos的自动注册流程

有趣味的能够下载源码调试 spring-cloud-alibaba 源码地址 版本 2021.1
本篇文章次要目标是阐明流程,所以除了办法名是源码以外,其余代码有简写或 重写 ,可看作 伪代码,只为了表白逻辑和展现流程。

一个代码块中调用办法的内容根本能够本代码块或上面一个代码块中找到。

服务注册

nacos 服务器就是一个 web 我的项目,对 nacos 的所有操作都就是发送一个 http 申请,所以只须要找到 spring-cloud-alibaba-nacos 在什么中央发送了这个申请。

  1. spring boot 启动时,会调用 spring 的 refresh 办法实现 spring 的启动,在启动的最初,调用 finishRefresh 办法。这个办法的最终目标是调用 spring 容器中所有 SmartLifecycle 实现类的 start 办法

    @Override
    public void refresh() throws BeansException, IllegalStateException {
         //...
         finishRefresh();
         //...
    }
    protected void finishRefresh() {
         //...
         // 初始化生命周期处理器, 默认为 DefaultLifecycleProcessor
         initLifecycleProcessor();
         // 调用生命周期处理器的 onRefresh
         getLifecycleProcessor().onRefresh();
         //...
    }
    public class DefaultLifecycleProcessor{
    
     @Override
     public void onRefresh() {startBeans(true);
     }
    
     private void startBeans(boolean autoStartupOnly) {
         // 获取 spring 容器中 SmartLifecycle 的实现类的 bean
         SmartLifecycle beans=getSmartLifecycleBeans();
         for(SmartLifecycle bean:beans){
             //SmartLifecycle 实现了 Phased 接口,能够返回一个 int 值,示意调用程序
             // 数字越小的越先调用
             int phase=beans.getPhase();
             // 把 bean 放入 LifecycleGroup 中,phase 雷同的放到同一个 LifecycleGroup
             // 目标在于能够对立调用 phase 雷同的 bean 的办法
             LifecycleGroup lifecycleGroups=new LifecycleGroup(phase,bean));
         }
         // 依据 phase 的值排序
         sort(lifecycleGroups);
         // 依据顺序调用 LifecycleGroup 的 start
         lifecycleGroups.start();}
    
     // 这是一个外部类
     private class LifecycleGroup {public void start() {doStart(bean);
         }
    
         private void doStart(){bean.start()
         }
     }
    }
  2. spring boot 提供了一个 SmartLifecycle 的实现类 WebServerStartStopLifecycle,并且重写了start 办法

    // 这个是 servlet 包下的,反应式的在 reactive 包下,同样也是公布事件
    package org.springframework.boot.web.servlet.context;
    
    public void start() {
         // 在 start 办法中公布了个事件,示意 Servlet web 服务器已初始化实现
         applicationContext.publishEvent(new ServletWebServerInitializedEvent());
    }
    // 这个事件的继承关系
    public class ServletWebServerInitializedEvent extends WebServerInitializedEvent
  3. spring-cloud 提供了个抽象类监听了 WebServerInitializedEvent 事件

    public abstract class AbstractAutoServiceRegistration<R extends Registration> implements ApplicationListener<WebServerInitializedEvent> {
     // 这里应用了装璜器模式,须要从子类中传入数据
     protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry, AutoServiceRegistrationProperties properties) {
         this.serviceRegistry = serviceRegistry;
         this.properties = properties;
     }
    
     public void onApplicationEvent(WebServerInitializedEvent event) {this.bind(event);
     }
    
     public void bind(WebServerInitializedEvent event) {this.start();
     }
    
     // 这里调用的是 nacos 实现类再调用 super,但子类中并没有什么重要逻辑,所以省略
     public void start() {this.register();
     }
    
     // 上方一顿调用,调到这里,这里就是 spring-cloud 提供的主动注册逻辑
     protected void register() {
         // 从子类获取 Registration 并应用子类传入的 serviceRegistry 进行注册
         this.serviceRegistry.register(this.getRegistration());
     }
    
     protected abstract R getRegistration();}

    简略看一下 RegistrationServiceRegistry两个接口

    1. public interface ServiceInstance {String getServiceId();
          String getHost();
          int getPort();}
      //Registration 的子类须要返回注册所需的根本信息
      public interface Registration extends ServiceInstance {}
    2. // 把 Registration 传入 register 办法,在子类中实现注册逻辑
      public interface ServiceRegistry<R extends Registration> {void register(R registration);
      }
  4. spring-cloud-alibaba-nacos 提供了 AbstractAutoServiceRegistration 的实现类,从继承关系来看,实质是一个监听了 WebServerInitializedEvent 的监听器

    public class NacosAutoServiceRegistration extends AbstractAutoServiceRegistration<Registration>{
     // 传入注册器和注册所需根本信息
     public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry,
                                         AutoServiceRegistrationProperties properties,
                                         NacosRegistration registration) {
         // 把 serviceRegistry 传入父类
         super(serviceRegistry, autoServiceRegistrationProperties);
         this.registration = registration;
     }
    
     @Override
     // 返回 registration
     protected NacosRegistration getRegistration() {return this.registration;}
    }
     

    NacosAutoServiceRegistration 对象是在主动配置类中创立的,springboot 主动配置的大抵逻辑

    springboot 启动时会获取 classpath*:META-INF/spring.factories 中的键值对

    再应用 spring 的通用解析逻辑去解析 value 所示意的类,实现解析的办法是:org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass

    #spring-cloud-starter-alibaba-nacos-discovery 包中的 spring.factories 文件,这只是其中一个 value
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration 
    public class NacosServiceRegistryAutoConfiguration {
    
     @Bean
     public NacosServiceRegistry nacosServiceRegistry() {return new NacosServiceRegistry();
     }
    
     @Bean
     public NacosRegistration nacosRegistration() {return new NacosRegistration();
     }
    
     @Bean
     public NacosAutoServiceRegistration nacosAutoServiceRegistration(
         NacosServiceRegistry registry,
         NacosRegistration registration) {return new NacosAutoServiceRegistration(registry, registration);
     }
    
    }
  5. nacos 的注册逻辑

    public class NacosServiceRegistry implements ServiceRegistry<Registration>{
        @Override
        public void register(Registration registration) {
            // 这个 NamingService 是 nacos-api 包中的类,是在主动配置类中 HealthIndicator
            // 创立的过程中被创立,这里是通过一个管理器去获取
            //NamingService 中蕴含了服务的获取、注册、删除等办法
            NacosNamingService namingService = namingService();
            // 应用 registration 创立一个服务实例
            Instance instance = createNacosInstance(registration);
            // 注册服务
            namingService.registerInstance(serviceId, group, instance);
    
    }
    public class NacosNamingService implements NamingService{
        @Override
        public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
    
            // 结构心跳信息
            BeatInfo beatInfo = beatReactor.buildBeatInfo(groupedServiceName, instance);
            // 发送心跳信息,也就是每隔一段时间就向 nacos 服务器发一个申请,// 服务器收到后解析申请就能晓得该服务没有下线
            //beatReactor 在结构器中被创立
            beatReactor.addBeatInfo(groupedServiceName, beatInfo);
    
            // 发送注册申请
            //serverProxy 在结构器中被创立
            serverProxy.registerService(groupedServiceName, groupName, instance);
        }
    }    
    // 这个代码块是发送心跳逻辑
    public class BeatReactor{public void addBeatInfo(String serviceName, BeatInfo beatInfo) {
           // 这是一个定时线程池,默认为虚拟机最大可用处理器数量的一半
           // 具体调用的是 Runtime.getRuntime().availableProcessors()数量包含超线程,但不是肯定精确。// 第一个参数是要执行的工作,第二个是延迟时间,默认 5 秒,第三个是工夫单位
           executorService.schedule(new BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit);
       }
    }
    
    class BeatTask implements Runnable {
       @Override
       public void run() {
           // 发送心跳信息
           serverProxy.sendBeat(beatInfo);
           // 这里又调用了本人,造成了递归,所以会每 5 秒就向 nacos 服务器发送信息
           executorService.schedule(new BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit);
       }
    }
    

    这是 nacos 官网提供的注册申请实例,所以只须要构建出这个申请发给 nacos 服务器就行了

    curl -X POST ‘http://127.0.0.1:8848/nacos/v…

    // 发送注册逻辑
    public class NamingProxy {public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
            //instance 中蕴含了注册服务所需的信息,信息起源为 NacosDiscoveryProperties 和其余中央
            // 应用传入的三个参数构建 params
            // 构建 header
            // 构建 uri
            // 应用 NacosRestTemplate 发送申请,外面应用了 JdkHttpClientRequest,// 再外面应用了 sun.net.www.protocol.http.HttpURLConnection
            // 申请往 nacos 服务器一发,完事。// 在这个 http 申请有返回值,nacos 也创立了一个 ResponseHandler 去把返回值解析为 HttpRestResult
            // 但在这个流程中最终没有应用返回值。// 心跳的发送也是 http 申请,所以与注册的逻辑是差不多的。reqApi(UtilAndComs.nacosUrlInstance, params, HttpMethod.POST);
        } 
    }

总结

一. spring,启动实现后调用 SmartLifecyclestart办法

二. spring-boot,提供了 SmartLifecycle 的实现类 WebServerStartStopLifecycle,在start 中公布了ServletWebServerInitializedEvent

三. spring-cloud,应用一个抽象类 AbstractAutoServiceRegistration 监听了 ServletWebServerInitializedEvent,通过调用子类的ServiceRegistryRegistration注册服务

四. spring-cloud-alibaba-nacos,提供了 AbstractAutoServiceRegistration 的实现类NacosServiceRegistryAutoConfiguration,并在主动配置类中初始化。

五. nacos,在 NacosServiceRegistryAutoConfiguration 中实现具体的 http 申请的构建与发送

退出移动版