spring cloud 服务注册和发现

fxz大约 19 分钟

本文只讨论spring cloud commons中关于服务注册、服务发现的规范定义以及spring cloud alibaba中nacos相应实现。关于nacos client以及 nacos service 中服务注册、发现的实现细节在nacos相关文章中分析。

spring cloud 服务注册和发现

SC 服务注册概述

以下都是spring cloud commons定义的服务注册的规范接口。

  • ServiceInstance 表示的是服务发现中的一个实例

    这个接口定义了类似于getHost,getIp获取注册实例host,ip等方法。

  • Registration一个标记接口,ServiceRegistry<R>这里面的R泛型就是Registration

    是springcloud定义的规范接口。

  • ServiceRegistry 服务注册,定义如何向注册中心进行注册,和取消注册

    这个接口定义了register服务注册,deregister服务取消注册等方法,入参是Registration。它是springcloud定义的规范接口。

  • AutoServiceRegistration 标识应用自动进行服务注册的接口,是springcloud定义的规范接口。

/**
 * 表示系统中服务的实例。
 *
 * @author Spencer Gibb
 * @author Tim Ysewyn
 */
public interface ServiceInstance {

    /**
     * @return The unique instance ID as registered.
     */
    default String getInstanceId() {
       return null;
    }

    /**
     * @return The service ID as registered.
     */
    String getServiceId();

    /**
     * @return The hostname of the registered service instance.
     */
    String getHost();

    /**
     * @return The port of the registered service instance.
     */
    int getPort();

    /**
     * @return Whether the port of the registered service instance uses HTTPS.
     */
    boolean isSecure();

    /**
     * @return The service URI address.
     */
    URI getUri();

    /**
     * @return The key / value pair metadata associated with the service instance.
     */
    Map<String, String> getMetadata();

    /**
     * @return The scheme of the service instance.
     */
    default String getScheme() {
       return null;
    }

}
/**
 * {@link ServiceRegistry} 使用的标记接口。
 *
 * @author Spencer Gibb
 * @since 1.2.0
 */
public interface Registration extends ServiceInstance {

}
/**
 * 向 Service Registry 注册和注销实例的接口。
 *
 * @param <R> registration meta data
 * @author Spencer Gibb
 * @since 1.2.0
 */
public interface ServiceRegistry<R extends Registration> {

    /**
     * Registers the registration. A registration typically has information about an
     * instance, such as its hostname and port.
     *
     * @param registration registration meta data
     */
    void register(R registration);

    /**
     * Deregisters the registration.
     *
     * @param registration registration meta data
     */
    void deregister(R registration);

    /**
     * Closes the ServiceRegistry. This is a lifecycle method.
     */
    void close();

    /**
     * Sets the status of the registration. The status values are determined by the
     * individual implementations.
     *
     * @param registration The registration to update.
     * @param status       The status to set.
     * @see org.springframework.cloud.client.serviceregistry.endpoint.ServiceRegistryEndpoint
     */
    void setStatus(R registration, String status);

    /**
     * Gets the status of a particular registration.
     *
     * @param registration The registration to query.
     * @param <T>          The type of the status.
     * @return The status of the registration.
     * @see org.springframework.cloud.client.serviceregistry.endpoint.ServiceRegistryEndpoint
     */
    <T> T getStatus(R registration);

}
public interface AutoServiceRegistration {

}
/**
 * {@link AutoServiceRegistration} 抽象模版方法。监听事件,回调注册方法。
 * <p>
 * TODO: Document the lifecycle.
 *
 * @param <R> Registration type passed to the {@link ServiceRegistry}.
 * @author Spencer Gibb
 */
public abstract class AbstractAutoServiceRegistration<R extends Registration>
       implements AutoServiceRegistration, ApplicationContextAware, ApplicationListener<WebServerInitializedEvent> {

    private static final Log logger = LogFactory.getLog(AbstractAutoServiceRegistration.class);

    private final ServiceRegistry<R> serviceRegistry;

    private boolean autoStartup = true;

    private AtomicBoolean running = new AtomicBoolean(false);

    private int order = 0;

    private ApplicationContext context;

    private Environment environment;

    private AtomicInteger port = new AtomicInteger(0);

    private AutoServiceRegistrationProperties properties;

    @Deprecated
    protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry) {
       this.serviceRegistry = serviceRegistry;
    }

    protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry,
                                    AutoServiceRegistrationProperties properties) {
       this.serviceRegistry = serviceRegistry;
       this.properties = properties;
    }

    protected ApplicationContext getContext() {
       return this.context;
    }

    /**
     * 自动服务注册的入口 监听{@link WebServerInitializedEvent}
     *
     * @param event the event to respond to
     */
    @Override
    @SuppressWarnings("deprecation")
    public void onApplicationEvent(WebServerInitializedEvent event) {
       bind(event);
    }

    @Deprecated
    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();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
       this.context = applicationContext;
       this.environment = this.context.getEnvironment();
    }

    @Deprecated
    protected Environment getEnvironment() {
       return this.environment;
    }

    @Deprecated
    protected AtomicInteger getPort() {
       return this.port;
    }

    public boolean isAutoStartup() {
       return this.autoStartup;
    }

    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
       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);
       }

    }

    /**
     * @return Whether the management service should be registered with the
     * {@link ServiceRegistry}.
     */
    protected boolean shouldRegisterManagement() {
       if (this.properties == null || this.properties.isRegisterManagement()) {
          return getManagementPort() != null && ManagementServerPortUtils.isDifferent(this.context);
       }
       return false;
    }

    /**
     * @return The object used to configure the registration.
     */
    @Deprecated
    protected abstract Object getConfiguration();

    /**
     * @return True, if this is enabled.
     */
    protected abstract boolean isEnabled();

    /**
     * @return The serviceId of the Management Service.
     */
    @Deprecated
    protected String getManagementServiceId() {
       // TODO: configurable management suffix
       return this.context.getId() + ":management";
    }

    /**
     * @return The service name of the Management Service.
     */
    @Deprecated
    protected String getManagementServiceName() {
       // TODO: configurable management suffix
       return getAppName() + ":management";
    }

    /**
     * @return The management server port.
     */
    @Deprecated
    protected Integer getManagementPort() {
       return ManagementServerPortUtils.getPort(this.context);
    }

    /**
     * @return The app name (currently the spring.application.name property).
     */
    @Deprecated
    protected String getAppName() {
       return this.environment.getProperty("spring.application.name", "application");
    }

    @PreDestroy
    public void destroy() {
       stop();
    }

    public boolean isRunning() {
       return this.running.get();
    }

    protected AtomicBoolean getRunning() {
       return this.running;
    }

    public int getOrder() {
       return this.order;
    }

    public int getPhase() {
       return 0;
    }

    protected ServiceRegistry<R> getServiceRegistry() {
       return this.serviceRegistry;
    }

    protected abstract R getRegistration();

    protected abstract R getManagementRegistration();

    /**
     * Register the local service with the {@link ServiceRegistry}.
     */
    protected void register() {
       this.serviceRegistry.register(getRegistration());
    }

    /**
     * Register the local management service with the {@link ServiceRegistry}.
     */
    protected void registerManagement() {
       R registration = getManagementRegistration();
       if (registration != null) {
          this.serviceRegistry.register(registration);
       }
    }

    /**
     * De-register the local service with the {@link ServiceRegistry}.
     */
    protected void deregister() {
       this.serviceRegistry.deregister(getRegistration());
    }

    /**
     * De-register the local management service with the {@link ServiceRegistry}.
     */
    protected void deregisterManagement() {
       R registration = getManagementRegistration();
       if (registration != null) {
          this.serviceRegistry.deregister(registration);
       }
    }

    public void stop() {
       if (this.getRunning().compareAndSet(true, false) && isEnabled()) {
          deregister();
          if (shouldRegisterManagement()) {
             deregisterManagement();
          }
          this.serviceRegistry.close();
       }
    }

}

SCA 服务注册概述

以下都是spring cloud alibaba实现的服务注册的规范接口。

  • NacosServiceInstance 表示的是服务发现中的一个实例

    这个接口定义了类似于getHost,getIp获取注册实例host,ip等方法。

  • NacosRegistration一个标记接口,标识服务注册实例。

  • NacosServiceRegistry 服务注册,定义如何向注册中心进行注册,和取消注册。

  • NacosAutoServiceRegistration 标识应用自动进行服务注册的接口。

自动配置类

NacosServiceRegistryAutoConfiguration向容器中注入了nacos关于服务注册的实现、nacos注册服务实例和nacos服务自动注册对象。


@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
       matchIfMissing = true)
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
       AutoServiceRegistrationAutoConfiguration.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);
    }

  	// 这也是为什么会自动注册服务的原因
    @Bean
    @ConditionalOnBean(AutoServiceRegistrationProperties.class)
    public NacosAutoServiceRegistration nacosAutoServiceRegistration(
          NacosServiceRegistry registry,
          AutoServiceRegistrationProperties autoServiceRegistrationProperties,
          NacosRegistration registration) {
       return new NacosAutoServiceRegistration(registry,
             autoServiceRegistrationProperties, registration);
    }

}

服务注册


/**
 * 自动注册nacos服务
 * @author xiaojing
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 */
public class NacosAutoServiceRegistration
       extends AbstractAutoServiceRegistration<Registration> {

    private static final Logger log = LoggerFactory
          .getLogger(NacosAutoServiceRegistration.class);

    private NacosRegistration registration;

    public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry,
          AutoServiceRegistrationProperties autoServiceRegistrationProperties,
          NacosRegistration registration) {
       super(serviceRegistry, autoServiceRegistrationProperties);
       this.registration = registration;
    }

    @Deprecated
    public void setPort(int port) {
       getPort().set(port);
    }

    @Override
    protected NacosRegistration getRegistration() {
       if (this.registration.getPort() < 0 && this.getPort().get() > 0) {
          this.registration.setPort(this.getPort().get());
       }
       Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set");
       return this.registration;
    }

    @Override
    protected NacosRegistration getManagementRegistration() {
       return null;
    }

    @Override
    protected void register() {
       // 检查是否开启服务自动注册
       if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
          log.debug("Registration disabled.");
          return;
       }
       if (this.registration.getPort() < 0) {
          this.registration.setPort(getPort().get());
       }

       // 注册服务
       super.register();
    }

    @Override
    protected void registerManagement() {
       if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
          return;
       }
       super.registerManagement();

    }

    @Override
    protected Object getConfiguration() {
       return this.registration.getNacosDiscoveryProperties();
    }

    @Override
    protected boolean isEnabled() {
       return this.registration.getNacosDiscoveryProperties().isRegisterEnabled();
    }

    @Override
    @SuppressWarnings("deprecation")
    protected String getAppName() {
       String appName = registration.getNacosDiscoveryProperties().getService();
       return StringUtils.isEmpty(appName) ? super.getAppName() : appName;
    }

    @EventListener
    public void onNacosDiscoveryInfoChangedEvent(NacosDiscoveryInfoChangedEvent event) {
       restart();
    }

    private void restart() {
       this.stop();
       this.start();
    }

}

NacosServiceRegistry核心是使用了nacos client的NamingService进行服务注册。

/**
 * @author xiaojing
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @author <a href="mailto:78552423@qq.com">eshun</a>
 * @author JAY
 */
public class NacosServiceRegistry implements ServiceRegistry<Registration> {

    private static final String STATUS_UP = "UP";

    private static final String STATUS_DOWN = "DOWN";

    private static final Logger log = LoggerFactory.getLogger(NacosServiceRegistry.class);

    private final NacosDiscoveryProperties nacosDiscoveryProperties;

    private final NacosServiceManager nacosServiceManager;

    public NacosServiceRegistry(NacosServiceManager nacosServiceManager,
          NacosDiscoveryProperties nacosDiscoveryProperties) {
       this.nacosDiscoveryProperties = nacosDiscoveryProperties;
       this.nacosServiceManager = nacosServiceManager;
    }

    @Override
    public void register(Registration registration) {

       if (StringUtils.isEmpty(registration.getServiceId())) {
          log.warn("No service to register for nacos client...");
          return;
       }

       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());
       }
       catch (Exception e) {
          if (nacosDiscoveryProperties.isFailFast()) {
             log.error("nacos registry, {} register failed...{},", serviceId,
                   registration.toString(), e);
             rethrowRuntimeException(e);
          }
          else {
             log.warn("Failfast is false. {} register failed...{},", serviceId,
                   registration.toString(), e);
          }
       }
    }

    @Override
    public void deregister(Registration registration) {

       log.info("De-registering from Nacos Server now...");

       if (StringUtils.isEmpty(registration.getServiceId())) {
          log.warn("No dom to de-register for nacos client...");
          return;
       }

       NamingService namingService = namingService();
       String serviceId = registration.getServiceId();
       String group = nacosDiscoveryProperties.getGroup();

       try {
          namingService.deregisterInstance(serviceId, group, registration.getHost(),
                registration.getPort(), nacosDiscoveryProperties.getClusterName());
       }
       catch (Exception e) {
          log.error("ERR_NACOS_DEREGISTER, de-register failed...{},",
                registration.toString(), e);
       }

       log.info("De-registration finished.");
    }

    @Override
    public void close() {
       try {
          nacosServiceManager.nacosServiceShutDown();
       }
       catch (NacosException e) {
          log.error("Nacos namingService shutDown failed", e);
       }
    }

    @Override
    public void setStatus(Registration registration, String status) {

       if (!STATUS_UP.equalsIgnoreCase(status)
             && !STATUS_DOWN.equalsIgnoreCase(status)) {
          log.warn("can't support status {},please choose UP or DOWN", status);
          return;
       }

       String serviceId = registration.getServiceId();

       Instance instance = getNacosInstanceFromRegistration(registration);

       if (STATUS_DOWN.equalsIgnoreCase(status)) {
          instance.setEnabled(false);
       }
       else {
          instance.setEnabled(true);
       }

       try {
          Properties nacosProperties = nacosDiscoveryProperties.getNacosProperties();
          nacosServiceManager.getNamingMaintainService(nacosProperties).updateInstance(
                serviceId, nacosDiscoveryProperties.getGroup(), instance);
       }
       catch (Exception e) {
          throw new RuntimeException("update nacos instance status fail", e);
       }

    }

    @Override
    public Object getStatus(Registration registration) {

       String serviceName = registration.getServiceId();
       String group = nacosDiscoveryProperties.getGroup();
       try {
          List<Instance> instances = namingService().getAllInstances(serviceName,
                group);
          for (Instance instance : instances) {
             if (instance.getIp().equalsIgnoreCase(nacosDiscoveryProperties.getIp())
                   && instance.getPort() == nacosDiscoveryProperties.getPort()) {
                return instance.isEnabled() ? STATUS_UP : STATUS_DOWN;
             }
          }
       }
       catch (Exception e) {
          log.error("get all instance of {} error,", serviceName, e);
       }
       return null;
    }

    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;
    }

    private NamingService namingService() {
       return nacosServiceManager.getNamingService();
    }

}

总结

通过ServiceRegistry实现执行最终的服务注册。AbstractAutoServiceRegistration会在监听事件最终回调服务注册方法实现服务注册。

Spring cloud servicediscovery

SC服务发现概述

  • DiscoveryClient是一个用于服务发现的接口,它允许应用程序查询服务注册中心以获取可用的服务实例信息。DiscoveryClient是Spring Cloud对服务发现功能的抽象,它可以与各种不同的服务注册中心集成,并提供统一的API来进行服务发现操作。
/**
 * 表示通常可用于发现服务的读取操作,例如 Netflix Eureka or consul.io.
 *
 * @author Spencer Gibb
 * @author Olga Maciaszek-Sharma
 * @author Chris Bono
 */
public interface DiscoveryClient extends Ordered {

    int DEFAULT_ORDER = 0;

    String description();

    /**
     * 获取与特定 serviceId 关联的所有 ServiceInstances。
     * @param serviceId The serviceId to query.
     * @return A List of ServiceInstance.
     */
    List<ServiceInstance> getInstances(String serviceId);

    /**
     * @return 所有已知的服务 ID。
     */
    List<String> getServices();

    default void probe() {
       getServices();
    }

    @Override
    default int getOrder() {
       return DEFAULT_ORDER;
    }

}
  • EnableDiscoveryClient作用就是import了EnableDiscoveryClientImportSelector。其中EnableDiscoveryClientImportSelector的作用:
    • 读取并注册 META-INF/spring.factories 中 key 是 EnableDiscoveryClient.class.getName() 的类信息。
    • 配置服务自动注册的信息。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {

    /**
     * 如果为 true,ServiceRegistry 将自动注册本地服务器。
     * @return - {@code true} 如果您想自动注册。
     */
    boolean autoRegister() default true;

}
/**
 * 作用一:读取并注册 META-INF/spring.factories 中 key 是 `EnableDiscoveryClient.class.getName()` 的类信息
 * 作用二:配置服务自动注册的信息
 * @author Spencer Gibb
 */
@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class EnableDiscoveryClientImportSelector extends SpringFactoryImportSelector<EnableDiscoveryClient> {

    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
       /**
        * 读取 META-INF/spring.factories 中 key 是 `EnableDiscoveryClient.class.getName()`
        * 的类信息
        */
       String[] imports = super.selectImports(metadata);

       AnnotationAttributes attributes = AnnotationAttributes
             .fromMap(metadata.getAnnotationAttributes(getAnnotationClass().getName(), true));

       // 注解的值是 true
       boolean autoRegister = attributes.getBoolean("autoRegister");

       if (autoRegister) {
          List<String> importsList = new ArrayList<>(Arrays.asList(imports));
          /**
           * 添加 AutoServiceRegistrationConfiguration 这个类,
           * 这个类的目的很简单,就是注册 AutoServiceRegistrationProperties 到BeanFactory中
           *        @EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
           * */
          importsList.add("org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
          imports = importsList.toArray(new String[0]);
       }
       else {
          Environment env = getEnvironment();
          if (ConfigurableEnvironment.class.isInstance(env)) {
             ConfigurableEnvironment configEnv = (ConfigurableEnvironment) env;
             LinkedHashMap<String, Object> map = new LinkedHashMap<>();
             map.put("spring.cloud.service-registry.auto-registration.enabled", false);
             MapPropertySource propertySource = new MapPropertySource("springCloudDiscoveryClient", map);
             configEnv.getPropertySources().addLast(propertySource);
          }

       }

       return imports;
    }

    @Override
    protected boolean isEnabled() {
       return getEnvironment().getProperty("spring.cloud.discovery.enabled", Boolean.class, Boolean.TRUE);
    }

    @Override
    protected boolean hasDefaultFactory() {
       return true;
    }

}

SCA服务发现概述

spring cloud alibaba实现了spring cloud规范,本质上还是使用nacos client 中的NamingService进行服务发现,这里只分析nacos的规范实现,nacos的细节在nacos相关文章中分析。

  • NacosDiscoveryClient实现了DiscoveryClient,本质上是用自己实现的serviceDiscovery进行服务发现,然后使用ServiceCache进行服务的缓存,这样可以在服务发现出现异常得时候使用缓存进行容错。
/**
 * @author xiaojing
 * @author renhaojun
 * @author echooymxq
 * @author freeman
 */
public class NacosDiscoveryClient implements DiscoveryClient {

    private static final Logger log = LoggerFactory.getLogger(NacosDiscoveryClient.class);

    /**
     * Nacos Discovery Client Description.
     */
    public static final String DESCRIPTION = "Spring Cloud Nacos Discovery Client";

    private NacosServiceDiscovery serviceDiscovery;

    @Value("${spring.cloud.nacos.discovery.failure-tolerance-enabled:false}")
    private boolean failureToleranceEnabled;

    public NacosDiscoveryClient(NacosServiceDiscovery nacosServiceDiscovery) {
       this.serviceDiscovery = nacosServiceDiscovery;
    }

    @Override
    public String description() {
       return DESCRIPTION;
    }

    @Override
    public List<ServiceInstance> getInstances(String serviceId) {
       try {
          return Optional.of(serviceDiscovery.getInstances(serviceId))
                .map(instances -> {
                   ServiceCache.setInstances(serviceId, instances);
                   return instances;
                }).get();
       }
       catch (Exception e) {
          if (failureToleranceEnabled) {
             return ServiceCache.getInstances(serviceId);
          }
          throw new RuntimeException(
                "Can not get hosts from nacos server. serviceId: " + serviceId, e);
       }
    }

    @Override
    public List<String> getServices() {
       try {
          return Optional.of(serviceDiscovery.getServices()).map(services -> {
             ServiceCache.setServiceIds(services);
             return services;
          }).get();
       }
       catch (Exception e) {
          log.error("get service name from nacos server failed.", e);
          return failureToleranceEnabled ? ServiceCache.getServiceIds()
                : Collections.emptyList();
       }
    }

}
  • NacosServiceDiscovery本质上用的NamingService进行服务发现,然后对服务实例进行属性映射处理。
/**
 * @author <a href="mailto:echooy.mxq@gmail.com">echooymxq</a>
 * @author changjin wei(魏昌进)
 **/
public class NacosServiceDiscovery {

    private NacosDiscoveryProperties discoveryProperties;

    private NacosServiceManager nacosServiceManager;

    public NacosServiceDiscovery(NacosDiscoveryProperties discoveryProperties,
          NacosServiceManager nacosServiceManager) {
       this.discoveryProperties = discoveryProperties;
       this.nacosServiceManager = nacosServiceManager;
    }

    /**
     * Return all instances for the given service.
     * @param serviceId id of service
     * @return list of instances
     * @throws NacosException nacosException
     */
    public List<ServiceInstance> getInstances(String serviceId) throws NacosException {
       String group = discoveryProperties.getGroup();
       List<Instance> instances = namingService().selectInstances(serviceId, group,
             true);
       return hostToServiceInstanceList(instances, serviceId);
    }

    /**
     * Return the names of all services.
     * @return list of service names
     * @throws NacosException nacosException
     */
    public List<String> getServices() throws NacosException {
       String group = discoveryProperties.getGroup();
       ListView<String> services = namingService().getServicesOfServer(1,
             Integer.MAX_VALUE, group);
       return services.getData();
    }

    public static List<ServiceInstance> hostToServiceInstanceList(
          List<Instance> instances, String serviceId) {
       List<ServiceInstance> result = new ArrayList<>(instances.size());
       for (Instance instance : instances) {
          ServiceInstance serviceInstance = hostToServiceInstance(instance, serviceId);
          if (serviceInstance != null) {
             result.add(serviceInstance);
          }
       }
       return result;
    }

    public static ServiceInstance hostToServiceInstance(Instance instance,
          String serviceId) {
       if (instance == null || !instance.isEnabled() || !instance.isHealthy()) {
          return null;
       }
       NacosServiceInstance nacosServiceInstance = new NacosServiceInstance();
       nacosServiceInstance.setHost(instance.getIp());
       nacosServiceInstance.setPort(instance.getPort());
       nacosServiceInstance.setServiceId(serviceId);
       nacosServiceInstance.setInstanceId(instance.getInstanceId());

       Map<String, String> metadata = new HashMap<>();
       metadata.put("nacos.instanceId", instance.getInstanceId());
       metadata.put("nacos.weight", instance.getWeight() + "");
       metadata.put("nacos.healthy", instance.isHealthy() + "");
       metadata.put("nacos.cluster", instance.getClusterName() + "");
       if (instance.getMetadata() != null) {
          metadata.putAll(instance.getMetadata());
       }
       metadata.put("nacos.ephemeral", String.valueOf(instance.isEphemeral()));
       nacosServiceInstance.setMetadata(metadata);

       if (metadata.containsKey("secure")) {
          boolean secure = Boolean.parseBoolean(metadata.get("secure"));
          nacosServiceInstance.setSecure(secure);
       }
       return nacosServiceInstance;
    }

    private NamingService namingService() {
       return nacosServiceManager.getNamingService();
    }

}

总结

spring cloud alibaba使用nacos实现了sc的服务发现规范,本质上还是用NamingService进行服务发现。