【Nacos】微服务注册在不同的group上,支持跨group服务发现,二次开发
创始人
2024-11-19 13:35:51

        Nacos具备微服务注册和发现,以及配置管理的功能,本文详情描述【注册和发现】的原理,以及基本使用,包括如何进行跨group注册和发现。

一、Nacos配置 
spring:   cloud:     nacos:       discovery:         server-addr: nacosIP地址:8849         namespace: dev         group: Product       config:         server-addr: nacosIP地址:8849         namespace: dev         group: Product         file-extension: yaml         refresh-enabled: true         enable-remote-sync-config: true         name: product.yaml
spring:   cloud:     nacos:       discovery:         server-addr: nacosIP地址:8849         namespace: dev         group: Order       config:         server-addr: nacosIP地址:8849         namespace: dev         group: Order         file-extension: yaml         refresh-enabled: true         enable-remote-sync-config: true         name: order.yaml         extension-configs:           - data-id: config-global.yaml             group: Order             refresh: true
一、NacosServiceDiscovery 中 getInstances 获取注册在nacos上的服务实例清单 
public List getInstances(String serviceId) throws NacosException {     String group = this.discoveryProperties.getGroup();     List instances = this.namingService().selectInstances(serviceId, group, true);     return hostToServiceInstanceList(instances, serviceId); }

  但是原始功能不支持跨group服务发现,所以我们需要重写 getInstances方法。

二、NacosServiceDiscoveryV2 继承 NacosServiceDiscovery,并重写 getInstances

import com.alibaba.cloud.nacos.NacosServiceInstance; import com.alibaba.cloud.nacos.NacosServiceManager; import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.ListView; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import org.springframework.cloud.client.ServiceInstance;  import java.util.*;  import static com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty; import static java.util.Objects.isNull;  /**  * @description: naocs服务发现重写  */ public class NacosServiceDiscoveryV2 extends NacosServiceDiscovery {      private final NacosDiscoveryPropertiesV2 discoveryProperties;      private final NacosShareProperties nacosShareProperties;      private final NacosServiceManager nacosServiceManager;      public NacosServiceDiscoveryV2(NacosDiscoveryPropertiesV2 discoveryProperties, NacosShareProperties nacosShareProperties, NacosServiceManager nacosServiceManager) {         super(discoveryProperties, nacosServiceManager);         this.discoveryProperties = discoveryProperties;         this.nacosShareProperties = nacosShareProperties;         this.nacosServiceManager = nacosServiceManager;     }      /**      * Return all instances for the given service.      * @param serviceId id of service      * @return list of instances      * @throws NacosException nacosException      */     @Override     public List getInstances(String serviceId) throws NacosException {         String group = discoveryProperties.getGroup();         List instances = discoveryProperties.namingServiceInstance()                 .selectInstances(serviceId, group, true);         if (isEmpty(instances)) {             Map> namespaceGroupMap = nacosShareProperties.getNamespaceGroupMap();             Map namespace2NamingServiceMap = discoveryProperties.shareNamingServiceInstances();             for (Map.Entry entry : namespace2NamingServiceMap.entrySet()) {                 String namespace;                 NamingService namingService;                 if (isNull(namespace = entry.getKey()) || isNull(namingService = entry.getValue()))                     continue;                 Set groupNames = namespaceGroupMap.get(namespace);                 List shareInstances;                 if (isEmpty(groupNames)) {                     shareInstances = namingService.selectInstances(serviceId, group, true);                     if (CollectionUtils.isNotEmpty(shareInstances))                         break;                 } else {                     shareInstances = new ArrayList<>();                     for (String groupName : groupNames) {                         List subShareInstances = namingService.selectInstances(serviceId, groupName, true);                         if (CollectionUtils.isNotEmpty(subShareInstances)) {                             shareInstances.addAll(subShareInstances);                         }                     }                 }                 if (CollectionUtils.isNotEmpty(shareInstances)) {                     instances = shareInstances;                     break;                 }             }         }         return hostToServiceInstanceList(instances, serviceId);     }      /**      * Return the names of all services.      * @return list of service names      * @throws NacosException nacosException      */     public List getServices() throws NacosException {         String group = discoveryProperties.getGroup();         ListView services = discoveryProperties.namingServiceInstance()                 .getServicesOfServer(1, Integer.MAX_VALUE, group);         return services.getData();     }      public static List hostToServiceInstanceList(             List instances, String serviceId) {         List 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);          Map 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() + "");         metadata.putAll(instance.getMetadata());         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(discoveryProperties.getNacosProperties());     } }

原理:

1、根据 serviceId 和 group 获取当前实例

2、获取所有group清单,并根据group找到group下所有实例

3、将group清单,加入到自己的实例清单中。

三、NacosDiscoveryPropertiesV2 继承 NacosDiscoveryProperties,服务发现属性重写 shareNamingServiceInstances、getNacosProperties方法

import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.nacos.api.NacosFactory; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.client.naming.utils.UtilAndComs; import org.slf4j.Logger; import org.slf4j.LoggerFactory;  import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate;  import static com.alibaba.nacos.api.PropertyKeyConst.*; import static java.util.Objects.nonNull;  /**  * @description: naocs服务发现属性重写  */ public class NacosDiscoveryPropertiesV2 extends NacosDiscoveryProperties {      private static final Logger log = LoggerFactory.getLogger(NacosDiscoveryPropertiesV2.class);      private final NacosShareProperties nacosShareProperties;      private static final Map NAMESPACE_TO_NAMING_SERVICE_MAP = new ConcurrentHashMap<>();      public NacosDiscoveryPropertiesV2(NacosShareProperties nacosShareProperties) {         super();         this.nacosShareProperties = nacosShareProperties;     }      public Map shareNamingServiceInstances() {         if (!NAMESPACE_TO_NAMING_SERVICE_MAP.isEmpty()) {             return new HashMap<>(NAMESPACE_TO_NAMING_SERVICE_MAP);         }         List entities = Optional.ofNullable(nacosShareProperties)                 .map(NacosShareProperties::getEntities).orElse(Collections.emptyList());         entities.stream().filter(entity -> nonNull(entity) && nonNull(entity.getNamespace()))                 .filter(distinctByKey(NacosShareProperties.NacosShareEntity::getNamespace))                 .forEach(entity -> {                     try {                         NamingService namingService = NacosFactory.createNamingService(getNacosProperties(entity.getNamespace()));                         if (namingService != null) {                             NAMESPACE_TO_NAMING_SERVICE_MAP.put(entity.getNamespace(), namingService);                         }                     } catch (Exception e) {                         log.error("create naming service error! properties={}, e=", this, e);                     }                 });         return new HashMap<>(NAMESPACE_TO_NAMING_SERVICE_MAP);     }     private static  Predicate distinctByKey(Function keyExtractor) {         Map seen = new ConcurrentHashMap<>();         return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;     }      private Properties getNacosProperties(String namespace) {         Properties properties = new Properties();         properties.put(SERVER_ADDR, getServerAddr());         properties.put(USERNAME, Objects.toString(getUsername(), ""));         properties.put(PASSWORD, Objects.toString(getPassword(), ""));         properties.put(NAMESPACE, namespace);         properties.put(UtilAndComs.NACOS_NAMING_LOG_NAME, getLogName());         String endpoint = getEndpoint();         if (endpoint.contains(":")) {             int index = endpoint.indexOf(":");             properties.put(ENDPOINT, endpoint.substring(0, index));             properties.put(ENDPOINT_PORT, endpoint.substring(index + 1));         }         else {             properties.put(ENDPOINT, endpoint);         }          properties.put(ACCESS_KEY, getAccessKey());         properties.put(SECRET_KEY, getSecretKey());         properties.put(CLUSTER_NAME, getClusterName());         properties.put(NAMING_LOAD_CACHE_AT_START, getNamingLoadCacheAtStart());  //        enrichNacosDiscoveryProperties(properties);         return properties;     } }

四、共享share属性类 NacosShareProperties

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration;  import java.util.*; import java.util.concurrent.ConcurrentHashMap;  import static java.util.Objects.nonNull;  /**  * 
  *  @description: 共享nacos属性  *  
*/ @Configuration @ConfigurationProperties(prefix = "nacos.share") public class NacosShareProperties { private final Map> NAMESPACE_TO_GROUP_NAME_MAP = new ConcurrentHashMap<>(); /** * 共享nacos实体列表 */ private List entities; public List getEntities() { return entities; } public void setEntities(List entities) { this.entities = entities; } public Map> getNamespaceGroupMap() { if (CollectionUtils.isEmpty(entities)) { return new HashMap<>(); } entities.stream().filter(entity -> nonNull(entity) && nonNull(entity.getNamespace())) .forEach(entity -> { Set groupNames = NAMESPACE_TO_GROUP_NAME_MAP.computeIfAbsent(entity.getNamespace(), k -> new HashSet<>()); if (nonNull(entity.getGroupNames())) groupNames.addAll(entity.getGroupNames()); }); return new HashMap<>(NAMESPACE_TO_GROUP_NAME_MAP); } @Override public String toString() { return "NacosShareProperties{" + "entities=" + entities + '}'; } /** * 共享nacos实体 */ public static final class NacosShareEntity { /** * 命名空间 */ private String namespace; /** * 分组 */ private List groupNames; public String getNamespace() { return namespace; } public void setNamespace(String namespace) { this.namespace = namespace; } public List getGroupNames() { return groupNames; } public void setGroupNames(List groupNames) { this.groupNames = groupNames; } @Override public String toString() { return "NacosShareEntity{" + "namespace='" + namespace + '\'' + ", groupNames=" + groupNames + '}'; } } }

五、整合配置类 NacosDiscoveryAutoConfigurationV2

import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled; import com.alibaba.cloud.nacos.NacosServiceManager; import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration; import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;  /**  * @Auther: yangjian  */ @Configuration(proxyBeanMethods = false) @ConditionalOnDiscoveryEnabled @ConditionalOnNacosDiscoveryEnabled @AutoConfigureBefore({NacosDiscoveryAutoConfiguration.class}) public class NacosDiscoveryAutoConfigurationV2 {     @Bean     @ConditionalOnMissingBean     public NacosDiscoveryPropertiesV2 nacosProperties(NacosShareProperties nacosShareProperties) {         return new NacosDiscoveryPropertiesV2(nacosShareProperties);     }      @Bean     @ConditionalOnMissingBean     public NacosServiceDiscovery nacosServiceDiscovery(NacosDiscoveryPropertiesV2 discoveryPropertiesV2             , NacosShareProperties nacosShareProperties, NacosServiceManager nacosServiceManager) {         return new NacosServiceDiscoveryV2(discoveryPropertiesV2, nacosShareProperties, nacosServiceManager);     } } 

相关内容

热门资讯

刚刚,Claude最新功能泄露... 新智元报道 编辑:定慧 大卫 【新智元导读】2026年5月4日,testingcatalog在An...
高分辨大宽带集成光子光谱仪成功... 麦姆斯咨询获悉,近日,中国科学院南京天文光学技术研究所天文光子学团队在面向天文观测的高分辨大宽带集成...
性价比高又稳定的云手机哪个好?... 作为搬了4年砖、踩过无数云手机坑的老玩家,今天直接给你们唠唠性价比高又稳定的云手机选法,全是实战干货...
以灵石破局,万物云参编国内首部... 4月23日,由低碳智慧建筑产业技术创新战略联盟与北京清华同衡规划设计研究院有限公司主办、万物云作为协...
专访 | CLA成功反哺全球 ... 2026年,是奔驰诞生的140周年,也是奔驰进入中国内地市场的20周年。 140年间,从第一款汽车问...