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 super T, ?> keyExtractor) { Map 四、共享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); } }