spring-cloud-alibaba-nacos的自动注册流程

元数据
English

有兴趣的可以下载源码调试 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请求的构建与发送

阅读 190
51 声望
0 粉丝
0 条评论
你知道吗?

51 声望
0 粉丝
宣传栏