org.apache.dubbo.registry.nacos.NacosRegistry Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dubbo-registry-nacos Show documentation
Show all versions of dubbo-registry-nacos Show documentation
The Nacos registry module of Dubbo project
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.registry.nacos;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.URLBuilder;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.url.component.DubboServiceAddressURL;
import org.apache.dubbo.common.url.component.ServiceConfigURL;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.common.utils.SystemPropertyConfigUtils;
import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.registry.NotifyListener;
import org.apache.dubbo.registry.Registry;
import org.apache.dubbo.registry.RegistryNotifier;
import org.apache.dubbo.registry.support.FailbackRegistry;
import org.apache.dubbo.registry.support.SkipFailbackWrapperException;
import org.apache.dubbo.rpc.RpcException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.listener.Event;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_NACOS_EXCEPTION;
import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.CONSUMERS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_ENABLE_EMPTY_PROTECTION;
import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
import static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.NACOE_REGISTER_COMPATIBLE;
import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_CONSUMER_URL_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;
import static org.apache.dubbo.registry.Constants.ADMIN_PROTOCOL;
import static org.apache.dubbo.registry.nacos.NacosServiceName.NAME_SEPARATOR;
import static org.apache.dubbo.registry.nacos.NacosServiceName.valueOf;
/**
* Nacos {@link Registry}
*
* @see #SERVICE_NAME_SEPARATOR
* @see #PAGINATION_SIZE
* @see #LOOKUP_INTERVAL
* @since 2.6.5
*/
public class NacosRegistry extends FailbackRegistry {
/**
* All supported categories
*/
private static final List ALL_SUPPORTED_CATEGORIES =
Arrays.asList(PROVIDERS_CATEGORY, CONSUMERS_CATEGORY, ROUTERS_CATEGORY, CONFIGURATORS_CATEGORY);
private static final int CATEGORY_INDEX = 0;
private static final int SERVICE_INTERFACE_INDEX = 1;
private static final int SERVICE_VERSION_INDEX = 2;
private static final int SERVICE_GROUP_INDEX = 3;
private static final String WILDCARD = "*";
private static final String UP = "UP";
/**
* The separator for service name Change a constant to be configurable, it's designed for Windows file name that is
* compatible with old Nacos binary release(< 0.6.1)
*/
private static final String SERVICE_NAME_SEPARATOR = SystemPropertyConfigUtils.getSystemProperty(
CommonConstants.ThirdPartyProperty.NACOS_SERVICE_NAME_SEPARATOR, ":");
/**
* The pagination size of query for Nacos service names(only for Dubbo-OPS)
*/
private static final int PAGINATION_SIZE = Integer.getInteger("nacos.service.names.pagination.size", 100);
/**
* The interval in second of lookup Nacos service names(only for Dubbo-OPS)
*/
private static final long LOOKUP_INTERVAL = Long.getLong("nacos.service.names.lookup.interval", 30);
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(NacosRegistry.class);
private final NacosNamingServiceWrapper namingService;
/**
* {@link ScheduledExecutorService} lookup Nacos service names(only for Dubbo-OPS)
*/
private volatile ScheduledExecutorService scheduledExecutorService;
private final Map> originToAggregateListener =
new ConcurrentHashMap<>();
private final Map>> nacosListeners =
new ConcurrentHashMap<>();
private final boolean supportLegacyServiceName;
public NacosRegistry(URL url, NacosNamingServiceWrapper namingService) {
super(url);
this.namingService = namingService;
this.supportLegacyServiceName = url.getParameter("nacos.subscribe.legacy-name", false);
}
@Override
public boolean isAvailable() {
return UP.equals(namingService.getServerStatus());
}
@Override
public List lookup(final URL url) {
if (url == null) {
throw new IllegalArgumentException("lookup url == null");
}
try {
List urls = new LinkedList<>();
Set serviceNames = getServiceNames(url, null);
for (String serviceName : serviceNames) {
List instances =
namingService.getAllInstances(serviceName, getUrl().getGroup(Constants.DEFAULT_GROUP));
urls.addAll(buildURLs(url, instances));
}
return urls;
} catch (SkipFailbackWrapperException exception) {
throw exception;
} catch (Exception cause) {
throw new RpcException(
"Failed to lookup " + url + " from nacos " + getUrl() + ", cause: " + cause.getMessage(), cause);
}
}
@Override
public void doRegister(URL url) {
try {
if (PROVIDER_SIDE.equals(url.getSide()) || getUrl().getParameter(REGISTER_CONSUMER_URL_KEY, false)) {
Instance instance = createInstance(url);
Set serviceNames = new HashSet<>();
// by default servicename is "org.apache.dubbo.xxService:1.0.0:"
String serviceName = getServiceName(url, false);
serviceNames.add(serviceName);
// in https://github.com/apache/dubbo/issues/14075
if (getUrl().getParameter(NACOE_REGISTER_COMPATIBLE, false)) {
// servicename is "org.apache.dubbo.xxService:1.0.0"
String compatibleServiceName = getServiceName(url, true);
serviceNames.add(compatibleServiceName);
}
/**
* namingService.registerInstance with
* {@link org.apache.dubbo.registry.support.AbstractRegistry#registryUrl}
* default {@link DEFAULT_GROUP}
*
* in https://github.com/apache/dubbo/issues/5978
*/
for (String service : serviceNames) {
namingService.registerInstance(service, getUrl().getGroup(Constants.DEFAULT_GROUP), instance);
}
} else {
logger.info("Please set 'dubbo.registry.parameters.register-consumer-url=true' to turn on consumer "
+ "url registration.");
}
} catch (SkipFailbackWrapperException exception) {
throw exception;
} catch (Exception cause) {
throw new RpcException(
"Failed to register " + url + " to nacos " + getUrl() + ", cause: " + cause.getMessage(), cause);
}
}
@Override
public void doUnregister(final URL url) {
try {
Instance instance = createInstance(url);
Set serviceNames = new HashSet<>();
// by default servicename is "org.apache.dubbo.xxService:1.0.0:"
String serviceName = getServiceName(url, false);
serviceNames.add(serviceName);
// in https://github.com/apache/dubbo/issues/14075
if (getUrl().getParameter(NACOE_REGISTER_COMPATIBLE, false)) {
// servicename is "org.apache.dubbo.xxService:1.0.0"
String serviceName1 = getServiceName(url, true);
serviceNames.add(serviceName1);
}
for (String service : serviceNames) {
namingService.deregisterInstance(
service, getUrl().getGroup(Constants.DEFAULT_GROUP), instance.getIp(), instance.getPort());
}
} catch (SkipFailbackWrapperException exception) {
throw exception;
} catch (Exception cause) {
throw new RpcException(
"Failed to unregister " + url + " to nacos " + getUrl() + ", cause: " + cause.getMessage(), cause);
}
}
@Override
public void doSubscribe(final URL url, final NotifyListener listener) {
NacosAggregateListener nacosAggregateListener = new NacosAggregateListener(listener);
originToAggregateListener
.computeIfAbsent(url, k -> new ConcurrentHashMap<>())
.put(listener, nacosAggregateListener);
Set serviceNames = getServiceNames(url, nacosAggregateListener);
doSubscribe(url, nacosAggregateListener, serviceNames);
}
private void doSubscribe(final URL url, final NacosAggregateListener listener, final Set serviceNames) {
try {
if (isServiceNamesWithCompatibleMode(url)) {
/**
* Get all instances with serviceNames to avoid instance overwrite and but with empty instance mentioned
* in https://github.com/apache/dubbo/issues/5885 and https://github.com/apache/dubbo/issues/5899
*
* namingService.getAllInstances with
* {@link org.apache.dubbo.registry.support.AbstractRegistry#registryUrl}
* default {@link DEFAULT_GROUP}
*
* in https://github.com/apache/dubbo/issues/5978
*/
for (String serviceName : serviceNames) {
List instances =
namingService.getAllInstances(serviceName, getUrl().getGroup(Constants.DEFAULT_GROUP));
notifySubscriber(url, serviceName, listener, instances);
}
for (String serviceName : serviceNames) {
subscribeEventListener(serviceName, url, listener);
}
} else {
for (String serviceName : serviceNames) {
List instances = new LinkedList<>();
instances.addAll(
namingService.getAllInstances(serviceName, getUrl().getGroup(Constants.DEFAULT_GROUP)));
String serviceInterface = serviceName;
String[] segments = serviceName.split(SERVICE_NAME_SEPARATOR, -1);
if (segments.length == 4) {
serviceInterface = segments[SERVICE_INTERFACE_INDEX];
}
URL subscriberURL = url.setPath(serviceInterface)
.addParameters(INTERFACE_KEY, serviceInterface, CHECK_KEY, String.valueOf(false));
notifySubscriber(subscriberURL, serviceName, listener, instances);
subscribeEventListener(serviceName, subscriberURL, listener);
}
}
} catch (SkipFailbackWrapperException exception) {
throw exception;
} catch (Throwable cause) {
throw new RpcException(
"Failed to subscribe " + url + " to nacos " + getUrl() + ", cause: " + cause.getMessage(), cause);
}
}
/**
* Since 2.7.6 the legacy service name will be added to serviceNames to fix bug with
* https://github.com/apache/dubbo/issues/5442
*
* @param url
* @return
*/
private boolean isServiceNamesWithCompatibleMode(final URL url) {
return !isAdminProtocol(url) && createServiceName(url).isConcrete();
}
@Override
public void doUnsubscribe(URL url, NotifyListener listener) {
if (isAdminProtocol(url)) {
shutdownServiceNamesLookup();
} else {
Map listenerMap = originToAggregateListener.get(url);
if (listenerMap == null) {
logger.warn(
REGISTRY_NACOS_EXCEPTION,
"",
"",
String.format(
"No aggregate listener found for url %s, "
+ "this service might have already been unsubscribed.",
url));
return;
}
NacosAggregateListener nacosAggregateListener = listenerMap.remove(listener);
if (nacosAggregateListener != null) {
Set serviceNames = nacosAggregateListener.getServiceNames();
try {
doUnsubscribe(url, nacosAggregateListener, serviceNames);
} catch (NacosException e) {
logger.error(
REGISTRY_NACOS_EXCEPTION,
"",
"",
"Failed to unsubscribe " + url + " to nacos " + getUrl() + ", cause: " + e.getMessage(),
e);
}
}
if (listenerMap.isEmpty()) {
originToAggregateListener.remove(url);
}
}
}
private void doUnsubscribe(
final URL url, final NacosAggregateListener nacosAggregateListener, final Set serviceNames)
throws NacosException {
for (String serviceName : serviceNames) {
unsubscribeEventListener(serviceName, url, nacosAggregateListener);
}
}
private void shutdownServiceNamesLookup() {
if (scheduledExecutorService != null) {
scheduledExecutorService.shutdown();
}
}
/**
* Get the service names from the specified {@link URL url}
*
* @param url {@link URL}
* @param listener {@link NotifyListener}
* @return non-null
*/
private Set getServiceNames(URL url, NacosAggregateListener listener) {
if (isAdminProtocol(url)) {
scheduleServiceNamesLookup(url, listener);
return getServiceNamesForOps(url);
} else {
return getServiceNames0(url);
}
}
private Set getServiceNames0(URL url) {
NacosServiceName serviceName = createServiceName(url);
final Set serviceNames;
if (serviceName.isConcrete()) { // is the concrete service name
serviceNames = new LinkedHashSet<>();
serviceNames.add(serviceName.toString());
if (supportLegacyServiceName) {
// Add the legacy service name since 2.7.6
String legacySubscribedServiceName = getLegacySubscribedServiceName(url);
if (!serviceName.toString().equals(legacySubscribedServiceName)) {
// avoid duplicated service names
serviceNames.add(legacySubscribedServiceName);
}
}
} else {
serviceNames = filterServiceNames(serviceName);
}
return serviceNames;
}
private Set filterServiceNames(NacosServiceName serviceName) {
try {
Set serviceNames = new LinkedHashSet<>();
serviceNames.addAll(
namingService
.getServicesOfServer(1, Integer.MAX_VALUE, getUrl().getGroup(Constants.DEFAULT_GROUP))
.getData()
.stream()
.filter(this::isConformRules)
.map(NacosServiceName::new)
.filter(serviceName::isCompatible)
.map(NacosServiceName::toString)
.collect(Collectors.toList()));
return serviceNames;
} catch (SkipFailbackWrapperException exception) {
throw exception;
} catch (Throwable cause) {
throw new RpcException(
"Failed to filter serviceName from nacos, url: " + getUrl() + ", serviceName: " + serviceName
+ ", cause: " + cause.getMessage(),
cause);
}
}
/**
* Verify whether it is a dubbo service
*
* @param serviceName
* @return
* @since 2.7.12
*/
private boolean isConformRules(String serviceName) {
return serviceName.split(NAME_SEPARATOR, -1).length == 4;
}
/**
* Get the legacy subscribed service name for compatible with Dubbo 2.7.3 and below
*
* @param url {@link URL}
* @return non-null
* @since 2.7.6
*/
private String getLegacySubscribedServiceName(URL url) {
StringBuilder serviceNameBuilder = new StringBuilder(DEFAULT_CATEGORY);
appendIfPresent(serviceNameBuilder, url, INTERFACE_KEY);
appendIfPresent(serviceNameBuilder, url, VERSION_KEY);
appendIfPresent(serviceNameBuilder, url, GROUP_KEY);
return serviceNameBuilder.toString();
}
private void appendIfPresent(StringBuilder target, URL url, String parameterName) {
String parameterValue = url.getParameter(parameterName);
if (!StringUtils.isBlank(parameterValue)) {
target.append(SERVICE_NAME_SEPARATOR).append(parameterValue);
}
}
private boolean isAdminProtocol(URL url) {
return ADMIN_PROTOCOL.equals(url.getProtocol());
}
private void scheduleServiceNamesLookup(final URL url, final NacosAggregateListener listener) {
if (scheduledExecutorService == null) {
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(
() -> {
Set serviceNames = getAllServiceNames();
filterData(serviceNames, serviceName -> {
boolean accepted = false;
for (String category : ALL_SUPPORTED_CATEGORIES) {
String prefix = category + SERVICE_NAME_SEPARATOR;
if (serviceName != null && serviceName.startsWith(prefix)) {
accepted = true;
break;
}
}
return accepted;
});
doSubscribe(url, listener, serviceNames);
},
LOOKUP_INTERVAL,
LOOKUP_INTERVAL,
TimeUnit.SECONDS);
}
}
/**
* Get the service names for Dubbo OPS
*
* @param url {@link URL}
* @return non-null
*/
private Set getServiceNamesForOps(URL url) {
Set serviceNames = getAllServiceNames();
filterServiceNames(serviceNames, url);
return serviceNames;
}
private Set getAllServiceNames() {
try {
final Set serviceNames = new LinkedHashSet<>();
int pageIndex = 1;
ListView listView = namingService.getServicesOfServer(
pageIndex, PAGINATION_SIZE, getUrl().getGroup(Constants.DEFAULT_GROUP));
// First page data
List firstPageData = listView.getData();
// Append first page into list
serviceNames.addAll(firstPageData);
// the total count
int count = listView.getCount();
// the number of pages
int pageNumbers = count / PAGINATION_SIZE;
int remainder = count % PAGINATION_SIZE;
// remain
if (remainder > 0) {
pageNumbers += 1;
}
// If more than 1 page
while (pageIndex < pageNumbers) {
listView = namingService.getServicesOfServer(
++pageIndex, PAGINATION_SIZE, getUrl().getGroup(Constants.DEFAULT_GROUP));
serviceNames.addAll(listView.getData());
}
return serviceNames;
} catch (SkipFailbackWrapperException exception) {
throw exception;
} catch (Throwable cause) {
throw new RpcException(
"Failed to get all serviceName from nacos, url: " + getUrl() + ", cause: " + cause.getMessage(),
cause);
}
}
private void filterServiceNames(Set serviceNames, URL url) {
final List categories = getCategories(url);
final String targetServiceInterface = url.getServiceInterface();
final String targetVersion = url.getVersion("");
final String targetGroup = url.getGroup("");
filterData(serviceNames, serviceName -> {
// split service name to segments
// (required) segments[0] = category
// (required) segments[1] = serviceInterface
// (optional) segments[2] = version
// (optional) segments[3] = group
String[] segments = serviceName.split(SERVICE_NAME_SEPARATOR, -1);
int length = segments.length;
if (length != 4) { // must present 4 segments
return false;
}
String category = segments[CATEGORY_INDEX];
if (!categories.contains(category)) { // no match category
return false;
}
String serviceInterface = segments[SERVICE_INTERFACE_INDEX];
// no match service interface
if (!WILDCARD.equals(targetServiceInterface)
&& !StringUtils.isEquals(targetServiceInterface, serviceInterface)) {
return false;
}
// no match service version
String version = segments[SERVICE_VERSION_INDEX];
if (!WILDCARD.equals(targetVersion) && !StringUtils.isEquals(targetVersion, version)) {
return false;
}
String group = segments[SERVICE_GROUP_INDEX];
return group == null || WILDCARD.equals(targetGroup) || StringUtils.isEquals(targetGroup, group);
});
}
private void filterData(Collection collection, NacosDataFilter filter) {
// remove if not accept
collection.removeIf(data -> !filter.accept(data));
}
@Deprecated
private List doGetServiceNames(URL url) {
List categories = getCategories(url);
List serviceNames = new ArrayList<>(categories.size());
for (String category : categories) {
final String serviceName = getServiceName(url, category);
serviceNames.add(serviceName);
}
return serviceNames;
}
@Override
public void destroy() {
super.destroy();
try {
this.namingService.shutdown();
} catch (NacosException e) {
logger.warn(REGISTRY_NACOS_EXCEPTION, "", "", "Unable to shutdown nacos naming service", e);
}
this.nacosListeners.clear();
}
private List toUrlWithEmpty(URL consumerURL, Collection instances) {
consumerURL = removeParamsFromConsumer(consumerURL);
List urls = buildURLs(consumerURL, instances);
// Nacos does not support configurators and routers from registry, so all notifications are of providers type.
if (urls.size() == 0 && !getUrl().getParameter(ENABLE_EMPTY_PROTECTION_KEY, DEFAULT_ENABLE_EMPTY_PROTECTION)) {
logger.warn(
REGISTRY_NACOS_EXCEPTION,
"",
"",
"Received empty url address list and empty protection is "
+ "disabled, will clear current available addresses");
URL empty = URLBuilder.from(consumerURL)
.setProtocol(EMPTY_PROTOCOL)
.addParameter(CATEGORY_KEY, DEFAULT_CATEGORY)
.build();
urls.add(empty);
}
return urls;
}
private List buildURLs(URL consumerURL, Collection instances) {
List urls = new LinkedList<>();
if (instances != null && !instances.isEmpty()) {
for (Instance instance : instances) {
URL url = buildURL(consumerURL, instance);
if (UrlUtils.isMatch(consumerURL, url)) {
urls.add(url);
}
}
}
return urls;
}
private void subscribeEventListener(String serviceName, final URL url, final NacosAggregateListener listener)
throws NacosException {
Map> listeners =
nacosListeners.computeIfAbsent(url, k -> new ConcurrentHashMap<>());
Map eventListeners = listeners.computeIfAbsent(listener, k -> new ConcurrentHashMap<>());
EventListener eventListener = eventListeners.computeIfAbsent(
serviceName, k -> new RegistryChildListenerImpl(serviceName, url, listener));
namingService.subscribe(serviceName, getUrl().getGroup(Constants.DEFAULT_GROUP), eventListener);
}
private void unsubscribeEventListener(String serviceName, final URL url, final NacosAggregateListener listener)
throws NacosException {
Map> listenerToServiceEvent = nacosListeners.get(url);
if (listenerToServiceEvent == null) {
return;
}
Map serviceToEventMap = listenerToServiceEvent.get(listener);
if (serviceToEventMap == null) {
return;
}
EventListener eventListener = serviceToEventMap.remove(serviceName);
if (eventListener == null) {
return;
}
namingService.unsubscribe(
serviceName, getUrl().getParameter(GROUP_KEY, Constants.DEFAULT_GROUP), eventListener);
if (serviceToEventMap.isEmpty()) {
listenerToServiceEvent.remove(listener);
}
if (listenerToServiceEvent.isEmpty()) {
nacosListeners.remove(url);
}
}
/**
* Notify the Enabled {@link Instance instances} to subscriber.
*
* @param url {@link URL}
* @param listener {@link NotifyListener}
* @param instances all {@link Instance instances}
*/
private void notifySubscriber(
URL url, String serviceName, NacosAggregateListener listener, Collection instances) {
List enabledInstances = new LinkedList<>(instances);
if (enabledInstances.size() > 0) {
// Instances
filterEnabledInstances(enabledInstances);
}
List aggregatedUrls =
toUrlWithEmpty(url, listener.saveAndAggregateAllInstances(serviceName, enabledInstances));
NacosRegistry.this.notify(url, listener.getNotifyListener(), aggregatedUrls);
}
/**
* Get the categories from {@link URL}
*
* @param url {@link URL}
* @return non-null array
*/
private List getCategories(URL url) {
return ANY_VALUE.equals(url.getServiceInterface()) ? ALL_SUPPORTED_CATEGORIES : Arrays.asList(DEFAULT_CATEGORY);
}
private URL buildURL(URL consumerURL, Instance instance) {
Map metadata = instance.getMetadata();
String protocol = metadata.get(PROTOCOL_KEY);
String path = metadata.get(PATH_KEY);
URL url = new ServiceConfigURL(protocol, instance.getIp(), instance.getPort(), path, instance.getMetadata());
return new DubboServiceAddressURL(url.getUrlAddress(), url.getUrlParam(), consumerURL, null);
}
private Instance createInstance(URL url) {
// Append default category if absent
String category = url.getCategory(DEFAULT_CATEGORY);
URL newURL = url.addParameter(CATEGORY_KEY, category);
newURL = newURL.addParameter(PROTOCOL_KEY, url.getProtocol());
newURL = newURL.addParameter(PATH_KEY, url.getPath());
String ip = url.getHost();
int port = url.getPort();
Instance instance = new Instance();
instance.setIp(ip);
instance.setPort(port);
instance.setMetadata(new HashMap<>(newURL.getParameters()));
return instance;
}
private NacosServiceName createServiceName(URL url) {
return valueOf(url);
}
private String getServiceName(URL url, boolean needCompatible) {
if (needCompatible) {
return getCompatibleServiceName(url, url.getCategory(DEFAULT_CATEGORY));
}
return getServiceName(url, url.getCategory(DEFAULT_CATEGORY));
}
private String getServiceName(URL url, String category) {
return category + SERVICE_NAME_SEPARATOR + url.getColonSeparatedKey();
}
private String getCompatibleServiceName(URL url, String category) {
return category + SERVICE_NAME_SEPARATOR + url.getCompatibleColonSeparatedKey();
}
private void filterEnabledInstances(Collection instances) {
filterData(instances, Instance::isEnabled);
}
/**
* A filter for Nacos data
*
* @since 2.6.5
*/
private interface NacosDataFilter {
/**
* Tests whether or not the specified data should be accepted.
*
* @param data The data to be tested
* @return true
if and only if data
* should be accepted
*/
boolean accept(T data);
}
private class RegistryChildListenerImpl implements EventListener {
private final RegistryNotifier notifier;
private final String serviceName;
private final URL consumerUrl;
private final NacosAggregateListener listener;
public RegistryChildListenerImpl(String serviceName, URL consumerUrl, NacosAggregateListener listener) {
this.serviceName = serviceName;
this.consumerUrl = consumerUrl;
this.listener = listener;
this.notifier = new RegistryNotifier(getUrl(), NacosRegistry.this.getDelay()) {
@Override
protected void doNotify(Object rawAddresses) {
List instances = (List) rawAddresses;
NacosRegistry.this.notifySubscriber(consumerUrl, serviceName, listener, instances);
}
};
}
@Override
public void onEvent(Event event) {
if (event instanceof NamingEvent) {
NamingEvent e = (NamingEvent) event;
notifier.notify(e.getInstances());
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
RegistryChildListenerImpl that = (RegistryChildListenerImpl) o;
return Objects.equals(serviceName, that.serviceName)
&& Objects.equals(consumerUrl, that.consumerUrl)
&& Objects.equals(listener, that.listener);
}
@Override
public int hashCode() {
return Objects.hash(serviceName, consumerUrl, listener);
}
}
}