Spring Cloud Alibaba Nacos 客户端服务注册解析

1、NacosServiceRegistryAutoConfiguration

自动配置类,注册bean。

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
      matchIfMissing = true)
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
      AutoServiceRegistrationAutoC@AutoConfigureAfteronfiguration.class,
      NacosDiscoveryAutoConfiguration.class })
public class NacosServiceRegistryAutoConfiguration {

   @Bean
   public NacosServiceRegistry nacosServiceRegistry(
         NacosServiceManager nacosServiceManager,
         NacosDiscoveryProperties nacosDiscoveryProperties) {
      return new NacosServiceRegistry(nacosServiceManager, nacosDiscoveryProperties);
   }

   @Bean
   @ConditionalOnBean(AutoServiceRegistrationProperties.class)
   public NacosRegistration nacosRegistration(
         ObjectProvider<List<NacosRegistrationCustomizer>> registrationCustomizers,
         NacosDiscoveryProperties nacosDiscoveryProperties,
         ApplicationContext context) {
      return new NacosRegistration(registrationCustomizers.getIfAvailable(),
            nacosDiscoveryProperties, context);
   }

    //nacos主动注册
   @Bean
   @ConditionalOnBean(AutoServiceRegistrationProperties.class)
   public NacosAutoServiceRegistration nacosAutoServiceRegistration(
         NacosServiceRegistry registry,
         AutoServiceRegistrationProperties autoServiceRegistrationProperties,
         NacosRegistration registration) {
      return new NacosAutoServiceRegistration(registry,
            autoServiceRegistrationProperties, registration);
   }

}

2、NacosAutoServiceRegistration

NacosAutoServiceRegistration的继承关系

public class NacosAutoServiceRegistration
      extends AbstractAutoServiceRegistration<Registration>
public abstract class AbstractAutoServiceRegistration<R extends Registration>
		implements AutoServiceRegistration, ApplicationContextAware,
		ApplicationListener<WebServerInitializedEvent>

NacosAutoServiceRegistration 的父类AbstractAutoServiceRegistration实现了AutoServiceRegistration和ApplicationListener接口。

2.1、AutoServiceRegistration

AutoServiceRegistrationAutoConfiguration类中要注入AutoServiceRegistration,如果没有实现类,就会报错。NacosServiceRegistryAutoConfiguration通过@AutoConfigureAfter注解指定AutoServiceRegistrationAutoConfiguration在NacosServiceRegistryAutoConfiguration后面注册。

@Configuration(proxyBeanMethods = false)
@Import(AutoServiceRegistrationConfiguration.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
      matchIfMissing = true)
public class AutoServiceRegistrationAutoConfiguration {

   @Autowired(required = false)
   private AutoServiceRegistration autoServiceRegistration;

   @Autowired
   private AutoServiceRegistrationProperties properties;

   @PostConstruct
   protected void init() {
      if (this.autoServiceRegistration == null && this.properties.isFailFast()) {
         throw new IllegalStateException("Auto Service Registration has "
               + "been requested, but there is no AutoServiceRegistration bean");
      }
   }

}

2.2、ApplicationListener

NacosAutoServiceRegistration实现了ApplicationListener,会监听WebServerInitializedEvent事件,当WebServer启动完成会发布这个事件。

//AbstractAutoServiceRegistration#onApplicationEvent
public void onApplicationEvent(WebServerInitializedEvent event) {
   bind(event);
}

onApplicationEvent调用了bind方法

//AbstractAutoServiceRegistration#bind
public void bind(WebServerInitializedEvent event) {
   ApplicationContext context = event.getApplicationContext();
   if (context instanceof ConfigurableWebServerApplicationContext) {
      if ("management".equals(((ConfigurableWebServerApplicationContext) context)
            .getServerNamespace())) {
         return;
      }
   }
    //设置端口号
   this.port.compareAndSet(0, event.getWebServer().getPort());
   //启动注册
   this.start();
}

调用start方法

//AbstractAutoServiceRegistration#start
public void start() {
    //不启用注册
   if (!isEnabled()) {
      if (logger.isDebugEnabled()) {
         logger.debug("Discovery Lifecycle disabled. Not starting");
      }
      return;
   }

   // only initialize if nonSecurePort is greater than 0 and it isn't already running
   // because of containerPortInitializer below
    //端口大于0,没有运行,容器的端口初始化在下面
   if (!this.running.get()) {
      this.context.publishEvent(
            new InstancePreRegisteredEvent(this, getRegistration()));
      //注册
       register();
      if (shouldRegisterManagement()) {
         registerManagement();
      }
      this.context.publishEvent(
            new InstanceRegisteredEvent<>(this, getConfiguration()));
      this.running.compareAndSet(false, true);
   }

}

是否启用注册

//com.alibaba.cloud.nacos.registry.NacosAutoServiceRegistration#isEnabled
protected boolean isEnabled() {
   return this.registration.getNacosDiscoveryProperties().isRegisterEnabled();
}
//AbstractAutoServiceRegistration#register
protected void register() {
   this.serviceRegistry.register(getRegistration());
}
//com.alibaba.cloud.nacos.registry.NacosServiceRegistry#register
public void register(Registration registration) {
	//没有serviceId,返回
   if (StringUtils.isEmpty(registration.getServiceId())) {
      log.warn("No service to register for nacos client...");
      return;
   }

    //Name server	NacosNamingService
   NamingService namingService = namingService();
   String serviceId = registration.getServiceId();
   String group = nacosDiscoveryProperties.getGroup();

    //获的实例信息
   Instance instance = getNacosInstanceFromRegistration(registration);

   try {
       //注册
      namingService.registerInstance(serviceId, group, instance);
      log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,
            instance.getIp(), instance.getPort());
   }
   ...
}
//com.alibaba.cloud.nacos.registry.NacosServiceRegistry#namingService
private NamingService namingService() {
   return nacosServiceManager
         .getNamingService(nacosDiscoveryProperties.getNacosProperties());
}
//NacosServiceRegistry#getNacosInstanceFromRegistration
private Instance getNacosInstanceFromRegistration(Registration registration) {
   Instance instance = new Instance();
   instance.setIp(registration.getHost());
   instance.setPort(registration.getPort());
   instance.setWeight(nacosDiscoveryProperties.getWeight());
   instance.setClusterName(nacosDiscoveryProperties.getClusterName());
   instance.setEnabled(nacosDiscoveryProperties.isInstanceEnabled());
   instance.setMetadata(registration.getMetadata());
   instance.setEphemeral(nacosDiscoveryProperties.isEphemeral());
   return instance;
}

注册

//com.alibaba.nacos.client.naming.NacosNamingService#registerInstance
public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
    NamingUtils.checkInstanceIsLegal(instance);
    //NamingClientProxyDelegate
    clientProxy.registerService(serviceName, groupName, instance);
}

NamingClientProxy 有一个抽象实现,AbstractNamingClientProxy,一个具体实现,NamingClientProxyDelegate,AbstractNamingClientProxy有两个具体实现NamingGrpcClientProxy,NamingHttpClientProxy

NacosNamingService构造器中调用init方法,init方法中将clientProxy初始化为NamingClientProxyDelegate。

//com.alibaba.nacos.client.naming.remote.NamingClientProxyDelegate#registerService
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
   //获得执行器,注册
    getExecuteClientProxy(instance).registerService(serviceName, groupName, instance);
}

获取执行器

//NamingClientProxyDelegate#getExecuteClientProxy
private NamingClientProxy getExecuteClientProxy(Instance instance) {
    //判断ephemeral是true还是false	是否临时节点
    //com.alibaba.cloud.nacos.NacosDiscoveryProperties#ephemeral  这个属性
    //默认true
    return instance.isEphemeral() ? grpcClientProxy : httpClientProxy;
}

执行具体执行器的注册方法

2.2.1、NamingGrpcClientProxy
//com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy#registerService
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);
}
//com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy#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);
    //注册成功,将redoData 的 registered 设置为true
    redoService.instanceRegistered(serviceName, groupName);
}
//com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy#requestToServer
private <T extends Response> T requestToServer(AbstractNamingRequest request, Class<T> responseClass)
        throws NacosException {
    try {
        request.putAllHeader(getSecurityHeaders());
        request.putAllHeader(getSpasHeaders(
                NamingUtils.getGroupedNameOptional(request.getServiceName(), request.getGroupName())));
        //调用grpc发请求
        Response response =
                requestTimeout < 0 ? rpcClient.request(request) : rpcClient.request(request, requestTimeout);
        if (ResponseCode.SUCCESS.getCode() != response.getResultCode()) {
            throw new NacosException(response.getErrorCode(), response.getMessage());
        }
        if (responseClass.isAssignableFrom(response.getClass())) {
            return (T) response;
        }
        NAMING_LOGGER.error("Server return unexpected response '{}', expected response should be '{}'",
                response.getClass().getName(), responseClass.getName());
    } catch (Exception e) {
        throw new NacosException(NacosException.SERVER_ERROR, "Request nacos server failed: ", e);
    }
    throw new NacosException(NacosException.SERVER_ERROR, "Server return invalid response");
}
public Response request(Request request, long timeoutMills) throws NacosException {
    int retryTimes = 0;
    Response response = null;
    Exception exceptionThrow = null;
    long start = System.currentTimeMillis();
    while (retryTimes < RETRY_TIMES && System.currentTimeMillis() < timeoutMills + start) {
        boolean waitReconnect = false;
        try {
            if (this.currentConnection == null || !isRunning()) {
                waitReconnect = true;
                throw new NacosException(NacosException.CLIENT_DISCONNECT,
                        "Client not connected,current status:" + rpcClientStatus.get());
            }
            
            //grpcConnection
            response = this.currentConnection.request(request, timeoutMills);
            if (response == null) {
                throw new NacosException(SERVER_ERROR, "Unknown Exception.");
            }
            if (response instanceof ErrorResponse) {
                if (response.getErrorCode() == NacosException.UN_REGISTER) {
                    synchronized (this) {
                        waitReconnect = true;
                        if (rpcClientStatus.compareAndSet(RpcClientStatus.RUNNING, RpcClientStatus.UNHEALTHY)) {
                            LoggerUtils.printIfErrorEnabled(LOGGER,
                                    "Connection is unregistered, switch server,connectionId={},request={}",
                                    currentConnection.getConnectionId(), request.getClass().getSimpleName());
                            switchServerAsync();
                        }
                    }
                    
                }
                throw new NacosException(response.getErrorCode(), response.getMessage());
            }
            // return response.
            lastActiveTimeStamp = System.currentTimeMillis();
            return response;
            
        } catch (Exception e) {
            if (waitReconnect) {
                try {
                    //wait client to re connect.
                    Thread.sleep(Math.min(100, timeoutMills / 3));
                } catch (Exception exception) {
                    //Do nothing.
                }
            }
            
            LoggerUtils.printIfErrorEnabled(LOGGER, "Send request fail, request={}, retryTimes={},errorMessage={}",
                    request, retryTimes, e.getMessage());
            
            exceptionThrow = e;
            
        }
        retryTimes++;
        
    }
    
    if (rpcClientStatus.compareAndSet(RpcClientStatus.RUNNING, RpcClientStatus.UNHEALTHY)) {
        switchServerAsyncOnRequestFail();
    }
    
    if (exceptionThrow != null) {
        throw (exceptionThrow instanceof NacosException) ? (NacosException) exceptionThrow
                : new NacosException(SERVER_ERROR, exceptionThrow);
    } else {
        throw new NacosException(SERVER_ERROR, "Request fail, unknown Error");
    }
}
public Response request(Request request, long timeouts) throws NacosException {
    Payload grpcRequest = GrpcUtils.convert(request);
    //实现了 Future	请求	9848,客户端grpc请求服务端的端口  9849是服务端请求服务端的端口
    ListenableFuture<Payload> requestFuture = grpcFutureServiceStub.request(grpcRequest);
    Payload grpcResponse;
    try {
        //获取请求结果
        grpcResponse = requestFuture.get(timeouts, TimeUnit.MILLISECONDS);
    } catch (Exception e) {
        throw new NacosException(NacosException.SERVER_ERROR, e);
    }

    return (Response) GrpcUtils.parse(grpcResponse);
}
2.2.2、NamingHttpClientProxy
//com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy#registerService
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
    
    NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance: {}", namespaceId, serviceName,
            instance);
    String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
    //临时节点 心跳
    if (instance.isEphemeral()) {
        BeatInfo beatInfo = beatReactor.buildBeatInfo(groupedServiceName, instance);
        beatReactor.addBeatInfo(groupedServiceName, beatInfo);
    }
    //包装参数
    final Map<String, String> params = new HashMap<String, String>(16);
    params.put(CommonParams.NAMESPACE_ID, namespaceId);
    params.put(CommonParams.SERVICE_NAME, groupedServiceName);
    params.put(CommonParams.GROUP_NAME, groupName);
    params.put(CommonParams.CLUSTER_NAME, instance.getClusterName());
    params.put(IP_PARAM, instance.getIp());
    params.put(PORT_PARAM, String.valueOf(instance.getPort()));
    params.put(WEIGHT_PARAM, String.valueOf(instance.getWeight()));
    params.put("enable", String.valueOf(instance.isEnabled()));
    params.put(HEALTHY_PARAM, String.valueOf(instance.isHealthy()));
    params.put(EPHEMERAL_PARAM, String.valueOf(instance.isEphemeral()));
    params.put(META_PARAM, JacksonUtils.toJson(instance.getMetadata()));
    //请求api   类似于http://127.0.0.1:8848/nacos/v1/ns/instance
    reqApi(UtilAndComs.nacosUrlInstance, params, HttpMethod.POST);
    
}
//com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy#reqApi
public String reqApi(String api, Map<String, String> params, String method) throws NacosException {
    return reqApi(api, params, Collections.EMPTY_MAP, method);
}
//com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy#reqApi
public String reqApi(String api, Map<String, String> params, Map<String, String> body, String method)
        throws NacosException {
    return reqApi(api, params, body, serverListManager.getServerList(), method);
}
//com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy#reqApi
public String reqApi(String api, Map<String, String> params, Map<String, String> body, List<String> servers,
        String method) throws NacosException {
    
    params.put(CommonParams.NAMESPACE_ID, getNamespaceId());
    
    if (CollectionUtils.isEmpty(servers) && !serverListManager.isDomain()) {
        throw new NacosException(NacosException.INVALID_PARAM, "no server available");
    }
    
    NacosException exception = new NacosException();
    
    if (serverListManager.isDomain()) {
        String nacosDomain = serverListManager.getNacosDomain();
        for (int i = 0; i < maxRetry; i++) {
            try {
                return callServer(api, params, body, nacosDomain, method);
            } catch (NacosException e) {
                exception = e;
                if (NAMING_LOGGER.isDebugEnabled()) {
                    NAMING_LOGGER.debug("request {} failed.", nacosDomain, e);
                }
            }
        }
    } else {
        Random random = new Random(System.currentTimeMillis());
        int index = random.nextInt(servers.size());
        
        for (int i = 0; i < servers.size(); i++) {
            String server = servers.get(index);
            try {
                return callServer(api, params, body, server, method);
            } catch (NacosException e) {
                exception = e;
                if (NAMING_LOGGER.isDebugEnabled()) {
                    NAMING_LOGGER.debug("request {} failed.", server, e);
                }
            }
            index = (index + 1) % servers.size();
        }
    }
    
    NAMING_LOGGER.error("request: {} failed, servers: {}, code: {}, msg: {}", api, servers, exception.getErrCode(),
            exception.getErrMsg());
    
    throw new NacosException(exception.getErrCode(),
            "failed to req API:" + api + " after all servers(" + servers + ") tried: " + exception.getMessage());
    
}
//com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy#callServer
public String callServer(String api, Map<String, String> params, Map<String, String> body, String curServer,
        String method) throws NacosException {
    long start = System.currentTimeMillis();
    long end = 0;
    params.putAll(getSecurityHeaders());
    params.putAll(getSpasHeaders(params.get(SERVICE_NAME_PARAM)));
    Header header = NamingHttpUtil.builderHeader();
    
    String url;
    if (curServer.startsWith(UtilAndComs.HTTPS) || curServer.startsWith(UtilAndComs.HTTP)) {
        url = curServer + api;
    } else {
        if (!InternetAddressUtil.containsPort(curServer)) {
            curServer = curServer + InternetAddressUtil.IP_PORT_SPLITER + serverPort;
        }
        url = NamingHttpClientManager.getInstance().getPrefix() + curServer + api;
    }
    
    try {
        //执行http请求
        HttpRestResult<String> restResult = nacosRestTemplate
                .exchangeForm(url, header, Query.newInstance().initParams(params), body, method, String.class);
        end = System.currentTimeMillis();
        
        MetricsMonitor.getNamingRequestMonitor(method, url, String.valueOf(restResult.getCode()))
                .observe(end - start);
        
        if (restResult.ok()) {
            return restResult.getData();
        }
        if (HttpStatus.SC_NOT_MODIFIED == restResult.getCode()) {
            return StringUtils.EMPTY;
        }
        throw new NacosException(restResult.getCode(), restResult.getMessage());
    } catch (Exception e) {
        NAMING_LOGGER.error("[NA] failed to request", e);
        throw new NacosException(NacosException.SERVER_ERROR, e);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值