You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2020/11/16 07:17:32 UTC
[dubbo] branch 3.0 updated: performance tuning,
reduce mem allocation of address URLs on consumer side (#6911)
This is an automated email from the ASF dual-hosted git repository.
liujun pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.0 by this push:
new d8fc808 performance tuning, reduce mem allocation of address URLs on consumer side (#6911)
d8fc808 is described below
commit d8fc808425c4f1db028c4fdab45d7082a957d760
Author: ken.lj <ke...@gmail.com>
AuthorDate: Mon Nov 16 15:12:23 2020 +0800
performance tuning, reduce mem allocation of address URLs on consumer side (#6911)
---
.../apache/dubbo/rpc/cluster/ClusterInvoker.java | 8 +
.../org/apache/dubbo/rpc/cluster/Directory.java | 5 +
.../cluster/configurator/AbstractConfigurator.java | 13 +-
.../rpc/cluster/directory/AbstractDirectory.java | 35 +-
.../cluster/interceptor/ClusterInterceptor.java | 4 +-
.../ConsumerContextClusterInterceptor.java | 6 +
.../cluster/support/AbstractClusterInvoker.java | 27 +
.../cluster/support/AvailableClusterInvoker.java | 2 +-
.../cluster/support/BroadcastClusterInvoker.java | 2 +-
.../cluster/support/FailbackClusterInvoker.java | 4 +-
.../cluster/support/FailfastClusterInvoker.java | 2 +-
.../cluster/support/FailoverClusterInvoker.java | 2 +-
.../cluster/support/FailsafeClusterInvoker.java | 2 +-
.../rpc/cluster/support/ForkingClusterInvoker.java | 2 +-
.../cluster/support/MergeableClusterInvoker.java | 9 +-
.../cluster/support/ProviderURLMergeProcessor.java | 16 +
.../cluster/support/wrapper/AbstractCluster.java | 34 +-
.../configurator/parser/ConfigParserTest.java | 17 +-
.../support/AbstractClusterInvokerTest.java | 25 +-
.../rpc/cluster/support/ClusterUtilsTest.java | 17 +-
.../src/main/java/org/apache/dubbo/common/URL.java | 780 +++++++++------------
.../java/org/apache/dubbo/common/URLBuilder.java | 37 +-
.../java/org/apache/dubbo/common/URLStrParser.java | 103 ++-
.../apache/dubbo/common/config/Environment.java | 9 +-
.../dubbo/common/constants/CommonConstants.java | 13 +
.../dubbo/common/constants/RegistryConstants.java | 2 +
.../dubbo/common/extension/ExtensionLoader.java | 13 +-
.../manager/DefaultExecutorRepository.java | 13 +-
.../threadpool/manager/ExecutorRepository.java | 8 +
.../url/component/DubboServiceAddressURL.java | 143 ++++
.../dubbo/common/url/component/PathURLAddress.java | 175 +++++
.../common/url/component/ServiceAddressURL.java | 218 ++++++
.../common/url/component/ServiceConfigURL.java | 134 ++++
.../dubbo/common/url/component/URLAddress.java | 260 +++++++
.../dubbo/common/url/component/URLItemCache.java | 67 ++
.../dubbo/common/url/component/URLParam.java | 286 ++++++++
.../org/apache/dubbo/common/utils/UrlUtils.java | 131 +++-
.../org/apache/dubbo/config/ApplicationConfig.java | 12 +
.../apache/dubbo/rpc/support/ProtocolUtils.java | 6 +-
.../dubbo/common/InterfaceAddressURLTest.java | 107 +++
.../org/apache/dubbo/common/URLBuilderTest.java | 6 +-
.../test/java/org/apache/dubbo/common/URLTest.java | 56 +-
.../support/AbortPolicyWithReportTest.java | 4 +-
.../apache/dubbo/common/utils/UrlUtilsTest.java | 2 +-
.../org/apache/dubbo/config/ReferenceConfig.java | 4 +-
.../org/apache/dubbo/config/ServiceConfig.java | 6 +-
.../dubbo/config/utils/ConfigValidationUtils.java | 9 +-
.../org/apache/dubbo/config/ServiceConfigTest.java | 4 +-
.../support/apollo/ApolloDynamicConfiguration.java | 8 +-
.../zookeeper/ZookeeperDynamicConfiguration.java | 2 +-
.../dubbo-demo-xml-provider-backend/pom.xml | 107 +++
.../demo/provider/chain/ChainApplication.java | 63 +-
.../demo/provider/chain/ChainServiceImpl.java | 69 +-
.../src/main/resources/dubbo.properties | 1 +
.../src/main/resources/log4j.properties | 7 +
.../main/resources/spring/dubbo-provider-chain.xml | 35 +
.../DynamicConfigurationServiceNameMapping.java | 10 +-
.../org/apache/dubbo/metadata/MetadataInfo.java | 13 +-
.../report/identifier/MetadataIdentifier.java | 13 +-
.../identifier/ServiceMetadataIdentifier.java | 9 +-
.../identifier/SubscriberMetadataIdentifier.java | 3 +-
.../report/support/AbstractMetadataReport.java | 11 +-
.../AbstractAbstractWritableMetadataService.java | 6 +-
.../metadata/test/JTestMetadataReport4Test.java | 4 +-
.../store/zookeeper/ZookeeperMetadataReport.java | 38 +-
.../dubbo/monitor/support/MonitorFilter.java | 10 +-
.../java/org/apache/dubbo/registry/Constants.java | 5 -
.../java/org/apache/dubbo/registry/Registry.java | 6 +
.../apache/dubbo/registry/RegistryNotifier.java | 83 +++
.../dubbo/registry/client/InstanceAddressURL.java | 12 +-
.../registry/client/ServiceDiscoveryRegistry.java | 3 +-
.../listener/ServiceInstancesChangedListener.java | 7 +-
.../metadata/MetadataServiceNameMapping.java | 10 +-
.../store/InMemoryWritableMetadataService.java | 3 +-
.../metadata/store/RemoteMetadataServiceImpl.java | 17 +-
.../DefaultMigrationAddressComparator.java | 4 +-
.../client/migration/MigrationInvoker.java | 27 +-
.../registry/integration/DynamicDirectory.java | 23 +-
.../registry/integration/RegistryDirectory.java | 87 +--
.../registry/integration/RegistryProtocol.java | 36 +-
.../dubbo/registry/support/AbstractRegistry.java | 18 +-
.../support/CacheableFailbackRegistry.java | 326 +++++++++
.../registry/CacheableFailbackRegistryTest.java} | 73 +-
.../registry/DelayedRegistryNotifierTest.java} | 57 +-
.../dubbo/registry/MockCacheableRegistryImpl.java} | 101 ++-
.../multiple/MultipleServiceDiscovery.java | 177 +++++
.../multiple/MultipleServiceDiscoveryFactory.java} | 62 +-
...g.apache.dubbo.registry.client.ServiceDiscovery | 1 +
...e.dubbo.registry.client.ServiceDiscoveryFactory | 1 +
.../multiple/MultipleRegistryTestUtil.java | 3 +-
.../apache/dubbo/registry/nacos/NacosRegistry.java | 90 ++-
.../dubbo/registry/nacos/NacosServiceName.java | 9 +-
.../registry/zookeeper/ZookeeperRegistry.java | 108 +--
.../zookeeper/ZookeeperServiceDiscovery.java | 52 +-
...e.dubbo.registry.client.ServiceDiscoveryFactory | 1 +
.../remoting/http/tomcat/TomcatHttpServer.java | 8 +-
.../dubbo/remoting/zookeeper/ZookeeperClient.java | 2 +
.../zookeeper/support/AbstractZookeeperClient.java | 2 +-
.../org/apache/dubbo/rpc/FilterChainBuilder.java | 60 +-
.../main/java/org/apache/dubbo/rpc/RpcContext.java | 9 +-
.../java/org/apache/dubbo/rpc/RpcInvocation.java | 6 +-
.../apache/dubbo/rpc/filter/AccessLogFilter.java | 6 +-
.../dubbo/rpc/filter/ConsumerContextFilter.java | 8 +-
.../apache/dubbo/rpc/protocol/AbstractInvoker.java | 11 +-
.../dubbo/rpc/protocol/AbstractProtocol.java | 5 +-
.../dubbo/rpc/protocol/ProtocolFilterWrapper.java | 103 +--
.../rpc/protocol/ProtocolListenerWrapper.java | 185 ++---
.../DefaultFilterChainBuilder.java} | 301 ++++----
.../org.apache.dubbo.rpc.FilterChainBuilder | 1 +
.../rpc/protocol/dubbo/CallbackServiceCodec.java | 2 +-
.../dubbo/rpc/protocol/dubbo/DubboInvoker.java | 6 +-
.../dubbo/rpc/protocol/dubbo/DubboProtocol.java | 4 +-
112 files changed, 3804 insertions(+), 1566 deletions(-)
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ClusterInvoker.java
index 0d5de6f..94237e2 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ClusterInvoker.java
@@ -38,4 +38,12 @@ public interface ClusterInvoker<T> extends Invoker<T> {
Directory<T> getDirectory();
boolean isDestroyed();
+
+ default boolean hasProxyInvokers() {
+ Directory<T> directory = getDirectory();
+ if (directory == null) {
+ return false;
+ }
+ return directory.hasInvokers();
+ }
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Directory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Directory.java
index e6a20fd..958cbde 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Directory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Directory.java
@@ -18,6 +18,7 @@ package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.Node;
import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException;
@@ -53,6 +54,10 @@ public interface Directory<T> extends Node {
boolean isDestroyed();
+ default boolean hasInvokers() {
+ return CollectionUtils.isNotEmpty(getAllInvokers());
+ }
+
void discordAddresses();
RouterChain<T> getRouterChain();
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java
index 166479c..4f27b08 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java
@@ -72,8 +72,8 @@ public abstract class AbstractConfigurator implements Configurator {
*/
String apiVersion = configuratorUrl.getParameter(CONFIG_VERSION_KEY);
if (StringUtils.isNotEmpty(apiVersion)) {
- String currentSide = url.getParameter(SIDE_KEY);
- String configuratorSide = configuratorUrl.getParameter(SIDE_KEY);
+ String currentSide = url.getSide();
+ String configuratorSide = configuratorUrl.getSide();
if (currentSide.equals(configuratorSide) && CONSUMER.equals(configuratorSide) && 0 == configuratorUrl.getPort()) {
url = configureIfMatch(NetUtils.getLocalHost(), url);
} else if (currentSide.equals(configuratorSide) && PROVIDER.equals(configuratorSide) && url.getPort() == configuratorUrl.getPort()) {
@@ -102,10 +102,10 @@ public abstract class AbstractConfigurator implements Configurator {
* 1.If it is a consumer ip address, the intention is to control a specific consumer instance, it must takes effect at the consumer side, any provider received this override url should ignore.
* 2.If the ip is 0.0.0.0, this override url can be used on consumer, and also can be used on provider.
*/
- if (url.getParameter(SIDE_KEY, PROVIDER).equals(CONSUMER)) {
+ if (url.getSide(PROVIDER).equals(CONSUMER)) {
// NetUtils.getLocalHost is the ip address consumer registered to registry.
return configureIfMatch(NetUtils.getLocalHost(), url);
- } else if (url.getParameter(SIDE_KEY, CONSUMER).equals(PROVIDER)) {
+ } else if (url.getSide(CONSUMER).equals(PROVIDER)) {
// take effect on all providers, so address must be 0.0.0.0, otherwise it won't flow to this if branch
return configureIfMatch(ANYHOST_VALUE, url);
}
@@ -118,9 +118,8 @@ public abstract class AbstractConfigurator implements Configurator {
// TODO, to support wildcards
String providers = configuratorUrl.getParameter(OVERRIDE_PROVIDERS_KEY);
if (StringUtils.isEmpty(providers) || providers.contains(url.getAddress()) || providers.contains(ANYHOST_VALUE)) {
- String configApplication = configuratorUrl.getParameter(APPLICATION_KEY,
- configuratorUrl.getUsername());
- String currentApplication = url.getParameter(APPLICATION_KEY, url.getUsername());
+ String configApplication = configuratorUrl.getApplication(configuratorUrl.getUsername());
+ String currentApplication = url.getApplication(url.getUsername());
if (configApplication == null || ANY_VALUE.equals(configApplication)
|| configApplication.equals(currentApplication)) {
Set<String> conditionKeys = new HashSet<String>();
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
index 8087576..6e7da3b 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
@@ -17,6 +17,7 @@
package org.apache.dubbo.rpc.cluster.directory;
import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.URLBuilder;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.StringUtils;
@@ -51,13 +52,12 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
private volatile boolean destroyed = false;
- private volatile URL consumerUrl;
-
- protected final Map<String, String> queryMap; // Initialization at construction time, assertion not null
- protected final String consumedProtocol;
+ protected volatile URL consumerUrl;
protected RouterChain<T> routerChain;
+ protected final Map<String, String> queryMap;
+
public AbstractDirectory(URL url) {
this(url, null);
}
@@ -67,17 +67,32 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
throw new IllegalArgumentException("url == null");
}
- queryMap = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY));
- String path = queryMap.get(PATH_KEY);
- this.consumedProtocol = this.queryMap.get(PROTOCOL_KEY) == null ? DUBBO : this.queryMap.get(PROTOCOL_KEY);
- this.url = url.removeParameter(REFER_KEY).removeParameter(MONITOR_KEY);
+ this.url = url.removeAttribute(REFER_KEY).removeParameter(MONITOR_KEY);
- this.consumerUrl = this.url.setProtocol(consumedProtocol).setPath(path == null ? queryMap.get(INTERFACE_KEY) : path).addParameters(queryMap)
- .removeParameter(MONITOR_KEY);
+ Object referParams = url.getAttribute(REFER_KEY);
+ if (referParams != null) {
+ this.queryMap = (Map<String, String>) referParams;
+ this.consumerUrl = turnRegistryUrlToConsumerUrl(url, queryMap);
+ } else {
+ this.queryMap = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY));
+ this.consumerUrl = url.addParameters(queryMap);
+ }
setRouterChain(routerChain);
}
+ private URL turnRegistryUrlToConsumerUrl(URL url, Map<String, String> queryMap) {
+ return URLBuilder.from(url)
+ .setHost(queryMap.get("register.ip"))
+ .setPort(0)
+ .setProtocol(queryMap.get(PROTOCOL_KEY) == null ? DUBBO : queryMap.get(PROTOCOL_KEY))
+ .setPath(queryMap.get(PATH_KEY) != null ? queryMap.get(PATH_KEY) : queryMap.get(INTERFACE_KEY))
+ .clearParameters()
+ .addParameters(queryMap)
+ .removeParameter(MONITOR_KEY)
+ .build();
+ }
+
@Override
public List<Invoker<T>> list(Invocation invocation) throws RpcException {
if (destroyed) {
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/interceptor/ClusterInterceptor.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/interceptor/ClusterInterceptor.java
index e989699..199361f 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/interceptor/ClusterInterceptor.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/interceptor/ClusterInterceptor.java
@@ -34,8 +34,8 @@ public interface ClusterInterceptor {
void after(AbstractClusterInvoker<?> clusterInvoker, Invocation invocation);
/**
- * Does not need to override this method, override {@link #before(AbstractClusterInvoker, Invocation)}
- * and {@link #after(AbstractClusterInvoker, Invocation)}, methods to add your own logic expected to be
+ * Override this method or {@link #before(AbstractClusterInvoker, Invocation)}
+ * and {@link #after(AbstractClusterInvoker, Invocation)} methods to add your own logic expected to be
* executed before and after invoke.
*
* @param clusterInvoker
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/interceptor/ConsumerContextClusterInterceptor.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/interceptor/ConsumerContextClusterInterceptor.java
index 4beb7a0..053bc87 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/interceptor/ConsumerContextClusterInterceptor.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/interceptor/ConsumerContextClusterInterceptor.java
@@ -21,6 +21,7 @@ import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
+import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;
@@ -43,6 +44,11 @@ public class ConsumerContextClusterInterceptor implements ClusterInterceptor, Cl
}
@Override
+ public Result intercept(AbstractClusterInvoker<?> clusterInvoker, Invocation invocation) throws RpcException {
+ return clusterInvoker.invoke(invocation);
+ }
+
+ @Override
public void onMessage(Result appResponse, AbstractClusterInvoker<?> invoker, Invocation invocation) {
RpcContext.getServerContext().setObjectAttachments(appResponse.getObjectAttachments());
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java
index e8e65fe..acd150f 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java
@@ -161,6 +161,7 @@ public abstract class AbstractClusterInvoker<T> implements ClusterInvoker<T> {
if (sticky) {
stickyInvoker = invoker;
}
+
return invoker;
}
@@ -196,6 +197,7 @@ public abstract class AbstractClusterInvoker<T> implements ClusterInvoker<T> {
logger.error("cluster reselect fail reason is :" + t.getMessage() + " if can not solve, you can set cluster.availablecheck=false in url", t);
}
}
+
return invoker;
}
@@ -290,6 +292,17 @@ public abstract class AbstractClusterInvoker<T> implements ClusterInvoker<T> {
}
}
+ protected Result invokeWithContext(Invoker<T> invoker, Invocation invocation) {
+ setContext(invoker);
+ Result result;
+ try {
+ result = invoker.invoke(invocation);
+ } finally {
+ clearContext(invoker);
+ }
+ return result;
+ }
+
protected abstract Result doInvoke(Invocation invocation, List<Invoker<T>> invokers,
LoadBalance loadbalance) throws RpcException;
@@ -319,4 +332,18 @@ public abstract class AbstractClusterInvoker<T> implements ClusterInvoker<T> {
return ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(DEFAULT_LOADBALANCE);
}
}
+
+
+ private void setContext(Invoker<T> invoker) {
+ RpcContext context = RpcContext.getContext();
+ context.setInvoker(invoker)
+ .setRemoteAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort())
+ .setRemoteApplicationName(invoker.getUrl().getRemoteApplication());
+ }
+
+ private void clearContext(Invoker<T> invoker) {
+ // do nothing
+ RpcContext context = RpcContext.getContext();
+ context.setInvoker(null);
+ }
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableClusterInvoker.java
index c75052c..81208c5 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableClusterInvoker.java
@@ -39,7 +39,7 @@ public class AvailableClusterInvoker<T> extends AbstractClusterInvoker<T> {
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
for (Invoker<T> invoker : invokers) {
if (invoker.isAvailable()) {
- return invoker.invoke(invocation);
+ return invokeWithContext(invoker, invocation);
}
}
throw new RpcException("No provider available in " + invokers);
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastClusterInvoker.java
index ab0623e..92a5743 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastClusterInvoker.java
@@ -49,7 +49,7 @@ public class BroadcastClusterInvoker<T> extends AbstractClusterInvoker<T> {
Result result = null;
for (Invoker<T> invoker : invokers) {
try {
- result = invoker.invoke(invocation);
+ result = invokeWithContext(invoker, invocation);
} catch (RpcException e) {
exception = e;
logger.warn(e.getMessage(), e);
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvoker.java
index 1528070..8bc4b13 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvoker.java
@@ -98,7 +98,7 @@ public class FailbackClusterInvoker<T> extends AbstractClusterInvoker<T> {
try {
checkInvokers(invokers, invocation);
invoker = select(loadbalance, invocation, invokers, null);
- return invoker.invoke(invocation);
+ return invokeWithContext(invoker, invocation);
} catch (Throwable e) {
logger.error("Failback to invoke method " + invocation.getMethodName() + ", wait for retry in background. Ignored exception: "
+ e.getMessage() + ", ", e);
@@ -141,7 +141,7 @@ public class FailbackClusterInvoker<T> extends AbstractClusterInvoker<T> {
try {
Invoker<T> retryInvoker = select(loadbalance, invocation, invokers, Collections.singletonList(lastInvoker));
lastInvoker = retryInvoker;
- retryInvoker.invoke(invocation);
+ invokeWithContext(retryInvoker, invocation);
} catch (Throwable e) {
logger.error("Failed retry to invoke method " + invocation.getMethodName() + ", waiting again.", e);
if ((++retryTimes) >= retries) {
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailfastClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailfastClusterInvoker.java
index a04bba0..d349808 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailfastClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailfastClusterInvoker.java
@@ -45,7 +45,7 @@ public class FailfastClusterInvoker<T> extends AbstractClusterInvoker<T> {
checkInvokers(invokers, invocation);
Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
try {
- return invoker.invoke(invocation);
+ return invokeWithContext(invoker, invocation);
} catch (Throwable e) {
if (e instanceof RpcException && ((RpcException) e).isBiz()) { // biz exception.
throw (RpcException) e;
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java
index 5efe0ce..cc3ed9c 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java
@@ -79,7 +79,7 @@ public class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T> {
invoked.add(invoker);
RpcContext.getContext().setInvokers((List) invoked);
try {
- Result result = invoker.invoke(invocation);
+ Result result = invokeWithContext(invoker, invocation);
if (le != null && logger.isWarnEnabled()) {
logger.warn("Although retry the method " + methodName
+ " in the service " + getInterface().getName()
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java
index 539686e..3548a67 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java
@@ -47,7 +47,7 @@ public class FailsafeClusterInvoker<T> extends AbstractClusterInvoker<T> {
try {
checkInvokers(invokers, invocation);
Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
- return invoker.invoke(invocation);
+ return invokeWithContext(invoker, invocation);
} catch (Throwable e) {
logger.error("Failsafe ignore exception: " + e.getMessage(), e);
return AsyncRpcResult.newDefaultAsyncResult(null, null, invocation); // ignore
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvoker.java
index 53a2c34..85a661b 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvoker.java
@@ -85,7 +85,7 @@ public class ForkingClusterInvoker<T> extends AbstractClusterInvoker<T> {
for (final Invoker<T> invoker : selected) {
executor.execute(() -> {
try {
- Result result = invoker.invoke(invocation);
+ Result result = invokeWithContext(invoker, invocation);
ref.offer(result);
} catch (Throwable e) {
int value = count.incrementAndGet();
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java
index 3b815ce..7bc1f94 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java
@@ -39,7 +39,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.rpc.Constants.ASYNC_KEY;
import static org.apache.dubbo.rpc.Constants.MERGER_KEY;
@@ -63,17 +62,17 @@ public class MergeableClusterInvoker<T> extends AbstractClusterInvoker<T> {
for (final Invoker<T> invoker : invokers) {
if (invoker.isAvailable()) {
try {
- return invoker.invoke(invocation);
+ return invokeWithContext(invoker, invocation);
} catch (RpcException e) {
if (e.isNoInvokerAvailableAfterFilter()) {
- log.debug("No available provider for service" + getUrl().getServiceKey() + " on group " + invoker.getUrl().getParameter(GROUP_KEY) + ", will continue to try another group.");
+ log.debug("No available provider for service" + getUrl().getServiceKey() + " on group " + invoker.getUrl().getGroup() + ", will continue to try another group.");
} else {
throw e;
}
}
}
}
- return invokers.iterator().next().invoke(invocation);
+ return invokeWithContext(invokers.iterator().next(), invocation);
}
Class<?> returnType;
@@ -88,7 +87,7 @@ public class MergeableClusterInvoker<T> extends AbstractClusterInvoker<T> {
for (final Invoker<T> invoker : invokers) {
RpcInvocation subInvocation = new RpcInvocation(invocation, invoker);
subInvocation.setAttachment(ASYNC_KEY, "true");
- results.put(invoker.getUrl().getServiceKey(), invoker.invoke(subInvocation));
+ results.put(invoker.getUrl().getServiceKey(), invokeWithContext(invoker, subInvocation));
}
Object result = null;
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ProviderURLMergeProcessor.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ProviderURLMergeProcessor.java
index 9c01aeb..9c91f38 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ProviderURLMergeProcessor.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ProviderURLMergeProcessor.java
@@ -1,3 +1,19 @@
+/*
+ * 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.rpc.cluster.support;
import org.apache.dubbo.common.URL;
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractCluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractCluster.java
index 0170026..6bdfeb7 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractCluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractCluster.java
@@ -17,7 +17,9 @@
package org.apache.dubbo.rpc.cluster.support.wrapper;
import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.rpc.FilterChainBuilder;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
@@ -30,12 +32,16 @@ import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;
import java.util.List;
+import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.FILTER_BUILDER_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_INTERCEPTOR_KEY;
public abstract class AbstractCluster implements Cluster {
private <T> Invoker<T> buildClusterInterceptors(AbstractClusterInvoker<T> clusterInvoker, String key) {
- AbstractClusterInvoker<T> last = clusterInvoker;
+// AbstractClusterInvoker<T> last = clusterInvoker;
+ AbstractClusterInvoker<T> last = new FilterInvoker<>(clusterInvoker);
List<ClusterInterceptor> interceptors = ExtensionLoader.getExtensionLoader(ClusterInterceptor.class).getActivateExtension(clusterInvoker.getUrl(), key);
if (!interceptors.isEmpty()) {
@@ -129,4 +135,30 @@ public abstract class AbstractCluster implements Cluster {
return null;
}
}
+
+ static class FilterInvoker<T> extends AbstractClusterInvoker<T> {
+ private Invoker<T> filterInvoker;
+
+ public FilterInvoker(AbstractClusterInvoker<T> invoker) {
+ filterInvoker = ExtensionLoader.getExtensionLoader(FilterChainBuilder.class)
+ .getExtension(invoker.getUrl().getParameter(FILTER_BUILDER_KEY, DEFAULT_KEY))
+ .buildInvokerChain(invoker, REFERENCE_FILTER_KEY, CommonConstants.CONSUMER);
+ }
+
+ @Override
+ public Result invoke(Invocation invocation) throws RpcException {
+ return filterInvoker.invoke(invocation);
+ }
+
+ /**
+ * The only purpose is to build a interceptor chain, so the cluster related logic doesn't matter.
+ * Use ClusterInvoker<T> to replace AbstractClusterInvoker<T> in the future.
+ */
+ @Override
+ protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
+ return null;
+ }
+ }
+
+
}
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/parser/ConfigParserTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/parser/ConfigParserTest.java
index d8d616f..7825b37 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/parser/ConfigParserTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/parser/ConfigParserTest.java
@@ -30,11 +30,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.List;
-import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.WEIGHT_KEY;
@@ -83,8 +80,8 @@ public class ConfigParserTest {
Assertions.assertNotNull(urls);
Assertions.assertEquals(1, urls.size());
URL url = urls.get(0);
- Assertions.assertEquals("testgroup", url.getParameter(GROUP_KEY));
- Assertions.assertEquals("1.0.0", url.getParameter(VERSION_KEY));
+ Assertions.assertEquals("testgroup", url.getGroup());
+ Assertions.assertEquals("1.0.0", url.getVersion());
}
}
@@ -97,7 +94,7 @@ public class ConfigParserTest {
URL url = urls.get(0);
Assertions.assertEquals("127.0.0.1", url.getAddress());
Assertions.assertEquals(6666, url.getParameter(TIMEOUT_KEY, 0));
- Assertions.assertNotNull(url.getParameter(APPLICATION_KEY));
+ Assertions.assertNotNull(url.getApplication());
}
}
@@ -123,7 +120,7 @@ public class ConfigParserTest {
Assertions.assertEquals("service1", url.getServiceInterface());
Assertions.assertEquals(6666, url.getParameter(TIMEOUT_KEY, 0));
Assertions.assertEquals("random", url.getParameter(LOADBALANCE_KEY));
- Assertions.assertEquals(url.getParameter(APPLICATION_KEY), "demo-consumer");
+ Assertions.assertEquals(url.getApplication(), "demo-consumer");
}
}
@@ -139,7 +136,7 @@ public class ConfigParserTest {
Assertions.assertEquals("*", url.getServiceInterface());
Assertions.assertEquals(6666, url.getParameter(TIMEOUT_KEY, 0));
Assertions.assertEquals("random", url.getParameter(LOADBALANCE_KEY));
- Assertions.assertEquals(url.getParameter(APPLICATION_KEY), "demo-consumer");
+ Assertions.assertEquals(url.getApplication(), "demo-consumer");
}
}
@@ -154,7 +151,7 @@ public class ConfigParserTest {
Assertions.assertEquals("*", url.getServiceInterface());
Assertions.assertEquals(6666, url.getParameter(TIMEOUT_KEY, 0));
Assertions.assertEquals("random", url.getParameter(LOADBALANCE_KEY));
- Assertions.assertEquals(url.getParameter(APPLICATION_KEY), "demo-consumer");
+ Assertions.assertEquals(url.getApplication(), "demo-consumer");
}
}
@@ -170,7 +167,7 @@ public class ConfigParserTest {
Assertions.assertEquals(6666, url.getParameter(TIMEOUT_KEY, 0));
Assertions.assertEquals("random", url.getParameter(LOADBALANCE_KEY));
Assertions.assertEquals("127.0.0.1:20880", url.getParameter(OVERRIDE_PROVIDERS_KEY));
- Assertions.assertEquals(url.getParameter(APPLICATION_KEY), "demo-consumer");
+ Assertions.assertEquals(url.getApplication(), "demo-consumer");
}
}
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java
index 5300058..6d19dd6 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java
@@ -17,9 +17,9 @@
package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.URLBuilder;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
@@ -42,12 +42,17 @@ import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
+import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_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.rpc.cluster.Constants.CLUSTER_AVAILABLE_CHECK_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.INVOCATION_NEED_MOCK;
import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
@@ -87,6 +92,10 @@ public class AbstractClusterInvokerTest {
@SuppressWarnings({"unchecked"})
@BeforeEach
public void setUp() throws Exception {
+ Map<String, Object> attributes = new HashMap<>();
+ attributes.put("application", "abstractClusterInvokerTest");
+ url = url.putAttribute(REFER_KEY, attributes);
+
invocation.setMethodName("sayHello");
invoker1 = mock(Invoker.class);
@@ -226,8 +235,8 @@ public class AbstractClusterInvokerTest {
@Test
public void testCloseAvailablecheck() {
LoadBalance lb = mock(LoadBalance.class);
- Map<String, String> queryMap = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY));
- URL tmpUrl = url.addParameters(queryMap).removeParameter(REFER_KEY).removeParameter(MONITOR_KEY);
+ Map<String, String> queryMap = (Map<String, String> )url.getAttribute(REFER_KEY);
+ URL tmpUrl = turnRegistryUrlToConsumerUrl(url, queryMap);
given(lb.select(invokers, tmpUrl, invocation)).willReturn(invoker1);
initlistsize5();
@@ -237,6 +246,16 @@ public class AbstractClusterInvokerTest {
}
+ private URL turnRegistryUrlToConsumerUrl(URL url, Map<String, String> queryMap) {
+ return URLBuilder.from(url)
+ .setProtocol(queryMap.get(PROTOCOL_KEY) == null ? DUBBO : queryMap.get(PROTOCOL_KEY))
+ .setPath(queryMap.get(PATH_KEY) != null ? queryMap.get(PATH_KEY) : queryMap.get(INTERFACE_KEY))
+ .clearParameters()
+ .addParameters(queryMap)
+ .removeParameter(MONITOR_KEY)
+ .build();
+ }
+
@Test
public void testDonotSelectAgainAndNoCheckAvailable() {
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java
index 01cb530..f0cedc0 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java
@@ -36,7 +36,6 @@ import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;
@@ -105,8 +104,8 @@ public class ClusterUtilsTest {
Assertions.assertEquals(url.getPassword(), "password");
Assertions.assertEquals(url.getParameter(PID_KEY), "1234");
Assertions.assertEquals(url.getParameter(THREADPOOL_KEY), "foo");
- Assertions.assertEquals(url.getParameter(APPLICATION_KEY), "consumer");
- Assertions.assertEquals(url.getParameter(REMOTE_APPLICATION_KEY), "provider");
+ Assertions.assertEquals(url.getApplication(), "consumer");
+ Assertions.assertEquals(url.getRemoteApplication(), "provider");
Assertions.assertEquals(url.getParameter(REFERENCE_FILTER_KEY), "filter1,filter2,filter3");
}
@@ -119,8 +118,8 @@ public class ClusterUtilsTest {
"&methods=remote&tag=remote×tamp=remote");
URL mergedUrl = ClusterUtils.mergeUrl(remoteURL, localURL.getParameters());
- Assertions.assertEquals(remoteURL.getParameter(VERSION_KEY), mergedUrl.getParameter(VERSION_KEY));
- Assertions.assertEquals(remoteURL.getParameter(GROUP_KEY), mergedUrl.getParameter(GROUP_KEY));
+ Assertions.assertEquals(remoteURL.getVersion(), mergedUrl.getVersion());
+ Assertions.assertEquals(remoteURL.getGroup(), mergedUrl.getGroup());
Assertions.assertEquals(remoteURL.getParameter(DUBBO_VERSION_KEY), mergedUrl.getParameter(DUBBO_VERSION_KEY));
Assertions.assertEquals(remoteURL.getParameter(RELEASE_KEY), mergedUrl.getParameter(RELEASE_KEY));
Assertions.assertEquals(remoteURL.getParameter(METHODS_KEY), mergedUrl.getParameter(METHODS_KEY));
@@ -133,8 +132,8 @@ public class ClusterUtilsTest {
remoteURL = URL.valueOf("dubbo://localhost:20880/DemoService");
mergedUrl = ClusterUtils.mergeUrl(remoteURL, localURL.getParameters());
- Assertions.assertEquals(mergedUrl.getParameter(VERSION_KEY),localURL.getParameter(VERSION_KEY));
- Assertions.assertEquals(mergedUrl.getParameter(GROUP_KEY),localURL.getParameter(GROUP_KEY));
+ Assertions.assertEquals(mergedUrl.getVersion(),localURL.getVersion());
+ Assertions.assertEquals(mergedUrl.getGroup(),localURL.getGroup());
Assertions.assertNull(mergedUrl.getParameter(DUBBO_VERSION_KEY));
Assertions.assertNull(mergedUrl.getParameter(RELEASE_KEY));
Assertions.assertNull(mergedUrl.getParameter(METHODS_KEY));
@@ -147,8 +146,8 @@ public class ClusterUtilsTest {
remoteURL = URL.valueOf("dubbo://localhost:20880/DemoService?key=value");
mergedUrl = ClusterUtils.mergeUrl(remoteURL, localURL.getParameters());
- Assertions.assertEquals(mergedUrl.getParameter(VERSION_KEY),localURL.getParameter(VERSION_KEY));
- Assertions.assertEquals(mergedUrl.getParameter(GROUP_KEY),localURL.getParameter(GROUP_KEY));
+ Assertions.assertEquals(mergedUrl.getVersion(),localURL.getVersion());
+ Assertions.assertEquals(mergedUrl.getGroup(),localURL.getGroup());
Assertions.assertNull(mergedUrl.getParameter(DUBBO_VERSION_KEY));
Assertions.assertNull(mergedUrl.getParameter(RELEASE_KEY));
Assertions.assertNull(mergedUrl.getParameter(METHODS_KEY));
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
index f227353..1be2800 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
@@ -19,8 +19,13 @@ package org.apache.dubbo.common;
import org.apache.dubbo.common.config.Configuration;
import org.apache.dubbo.common.config.InmemoryConfiguration;
import org.apache.dubbo.common.constants.RemotingConstants;
+import org.apache.dubbo.common.url.component.PathURLAddress;
+import org.apache.dubbo.common.url.component.ServiceConfigURL;
+import org.apache.dubbo.common.url.component.URLAddress;
+import org.apache.dubbo.common.url.component.URLParam;
import org.apache.dubbo.common.utils.ArrayUtils;
import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.LRUCache;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.common.utils.StringUtils;
@@ -38,25 +43,28 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
+import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
-import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_APPLICATION_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
import static org.apache.dubbo.common.convert.Converter.convertIfPossible;
import static org.apache.dubbo.common.utils.StringUtils.isBlank;
@@ -97,23 +105,10 @@ class URL implements Serializable {
private static final long serialVersionUID = -1985165475234910535L;
- protected String protocol;
+ private static Map<String, URL> cachedURLs = new LRUCache<>();
- protected String username;
-
- protected String password;
-
- // by default, host to registry
- protected String host;
-
- // by default, port to registry
- protected int port;
-
- protected String path;
-
- private final Map<String, String> parameters;
-
- private final Map<String, Map<String, String>> methodParameters;
+ private final URLAddress urlAddress;
+ private final URLParam urlParam;
// ==== cache ====
@@ -123,31 +118,17 @@ class URL implements Serializable {
private volatile transient Map<String, URL> urls;
- private volatile transient String ip;
-
- private volatile transient String full;
-
- private volatile transient String identity;
-
- private volatile transient String parameter;
-
- private volatile transient String string;
-
private transient String serviceKey;
private transient String protocolServiceKey;
- private transient String address;
-
protected URL() {
- this.protocol = null;
- this.username = null;
- this.password = null;
- this.host = null;
- this.port = 0;
- this.address = null;
- this.path = null;
- this.parameters = null;
- this.methodParameters = null;
+ this.urlAddress = null;
+ this.urlParam = null;
+ }
+
+ public URL(URLAddress urlAddress, URLParam urlParam) {
+ this.urlAddress = urlAddress;
+ this.urlParam = urlParam;
}
public URL(String protocol, String host, int port) {
@@ -189,176 +170,70 @@ class URL implements Serializable {
int port,
String path,
Map<String, String> parameters) {
- this(protocol, username, password, host, port, path, parameters, toMethodParameters(parameters));
+ if (StringUtils.isEmpty(username)
+ && StringUtils.isNotEmpty(password)) {
+ throw new IllegalArgumentException("Invalid url, password without username!");
+ }
+
+ this.urlAddress = new PathURLAddress(protocol, username, password, path, host, port);
+ this.urlParam = new URLParam(parameters);
}
- public URL(String protocol,
+ protected URL(String protocol,
String username,
String password,
String host,
int port,
String path,
Map<String, String> parameters,
- Map<String, Map<String, String>> methodParameters) {
+ boolean modifiable) {
if (StringUtils.isEmpty(username)
&& StringUtils.isNotEmpty(password)) {
throw new IllegalArgumentException("Invalid url, password without username!");
}
- this.protocol = protocol;
- this.username = username;
- this.password = password;
- this.host = host;
- this.port = Math.max(port, 0);
- this.address = getAddress(this.host, this.port);
- // trim the beginning "/"
- while (path != null && path.startsWith("/")) {
- path = path.substring(1);
- }
- this.path = path;
- if (parameters == null) {
- parameters = new HashMap<>();
- } else {
- parameters = new HashMap<>(parameters);
- }
- this.parameters = Collections.unmodifiableMap(parameters);
- this.methodParameters = Collections.unmodifiableMap(methodParameters);
+ this.urlAddress = new PathURLAddress(protocol, username, password, path, host, port);
+ this.urlParam = new URLParam(parameters);
}
- private static String getAddress(String host, int port) {
- return port <= 0 ? host : host + ':' + port;
+ public static URL cacheableValueOf(String url) {
+ URL cachedURL = cachedURLs.get(url);
+ if (cachedURL != null) {
+ return cachedURL;
+ }
+ cachedURL = valueOf(url, false);
+ cachedURLs.put(url, cachedURL);
+ return cachedURL;
}
/**
- * NOTICE: This method allocate too much objects, we can use {@link URLStrParser#parseDecodedStr(String)} instead.
- * <p>
- * Parse url string
+ * parse decoded url string, formatted dubbo://host:port/path?param=value, into strutted URL.
*
- * @param url URL string
- * @return URL instance
- * @see URL
+ * @param url, decoded url string
+ * @return
*/
public static URL valueOf(String url) {
- if (url == null || (url = url.trim()).length() == 0) {
- throw new IllegalArgumentException("url == null");
- }
- String protocol = null;
- String username = null;
- String password = null;
- String host = null;
- int port = 0;
- String path = null;
- Map<String, String> parameters = null;
- int i = url.indexOf('?'); // separator between body and parameters
- if (i >= 0) {
- String[] parts = url.substring(i + 1).split("&");
- parameters = new HashMap<>();
- for (String part : parts) {
- part = part.trim();
- if (part.length() > 0) {
- int j = part.indexOf('=');
- if (j >= 0) {
- String key = part.substring(0, j);
- String value = part.substring(j + 1);
- parameters.put(key, value);
- // compatible with lower versions registering "default." keys
- if (key.startsWith(DEFAULT_KEY_PREFIX)) {
- parameters.putIfAbsent(key.substring(DEFAULT_KEY_PREFIX.length()), value);
- }
- } else {
- parameters.put(part, part);
- }
- }
- }
- url = url.substring(0, i);
- }
- i = url.indexOf("://");
- if (i >= 0) {
- if (i == 0) {
- throw new IllegalStateException("url missing protocol: \"" + url + "\"");
- }
- protocol = url.substring(0, i);
- url = url.substring(i + 3);
- } else {
- // case: file:/path/to/file.txt
- i = url.indexOf(":/");
- if (i >= 0) {
- if (i == 0) {
- throw new IllegalStateException("url missing protocol: \"" + url + "\"");
- }
- protocol = url.substring(0, i);
- url = url.substring(i + 1);
- }
- }
-
- i = url.indexOf('/');
- if (i >= 0) {
- path = url.substring(i + 1);
- url = url.substring(0, i);
- }
- i = url.lastIndexOf('@');
- if (i >= 0) {
- username = url.substring(0, i);
- int j = username.indexOf(':');
- if (j >= 0) {
- password = username.substring(j + 1);
- username = username.substring(0, j);
- }
- url = url.substring(i + 1);
- }
- i = url.lastIndexOf(':');
- if (i >= 0 && i < url.length() - 1) {
- if (url.lastIndexOf('%') > i) {
- // ipv6 address with scope id
- // e.g. fe80:0:0:0:894:aeec:f37d:23e1%en0
- // see https://howdoesinternetwork.com/2013/ipv6-zone-id
- // ignore
- } else {
- port = Integer.parseInt(url.substring(i + 1));
- url = url.substring(0, i);
- }
- }
- if (url.length() > 0) {
- host = url;
- }
-
- return new URL(protocol, username, password, host, port, path, parameters);
+ return valueOf(url, false);
}
- public static Map<String, Map<String, String>> toMethodParameters(Map<String, String> parameters) {
- Map<String, Map<String, String>> methodParameters = new HashMap<>();
- if (parameters == null) {
- return methodParameters;
- }
+ /**
+ * parse normal or encoded url string into strutted URL:
+ * - dubbo://host:port/path?param=value
+ * - URL.encode("dubbo://host:port/path?param=value")
+ *
+ * @param url, url string
+ * @param encoded, encoded or decoded
+ * @return
+ */
+ public static URL valueOf(String url, boolean encoded) {
+ return valueOf(url, encoded, false);
+ }
- String methodsString = parameters.get(METHODS_KEY);
- if (StringUtils.isNotEmpty(methodsString)) {
- List<String> methods = StringUtils.splitToList(methodsString, ',');
- for (Map.Entry<String, String> entry : parameters.entrySet()) {
- String key = entry.getKey();
- for (int i = 0; i < methods.size(); i++) {
- String method = methods.get(i);
- int methodLen = method.length();
- if (key.length() > methodLen
- && key.startsWith(method)
- && key.charAt(methodLen) == '.') {//equals to: key.startsWith(method + '.')
- String realKey = key.substring(methodLen + 1);
- URL.putMethodParameter(method, realKey, entry.getValue(), methodParameters);
- }
- }
- }
- } else {
- for (Map.Entry<String, String> entry : parameters.entrySet()) {
- String key = entry.getKey();
- int methodSeparator = key.indexOf('.');
- if (methodSeparator > 0) {
- String method = key.substring(0, methodSeparator);
- String realKey = key.substring(methodSeparator + 1);
- URL.putMethodParameter(method, realKey, entry.getValue(), methodParameters);
- }
- }
+ public static URL valueOf(String url, boolean encoded, boolean modifiable) {
+ if (encoded) {
+ return URLStrParser.parseEncodedStr(url, modifiable);
}
- return methodParameters;
+ return URLStrParser.parseDecodedStr(url, modifiable);
}
public static URL valueOf(String url, String... reserveParams) {
@@ -398,8 +273,8 @@ class URL implements Serializable {
}
}
}
- return newMap.isEmpty() ? new URL(url.getProtocol(), url.getUsername(), url.getPassword(), url.getHost(), url.getPort(), url.getPath())
- : new URL(url.getProtocol(), url.getUsername(), url.getPassword(), url.getHost(), url.getPort(), url.getPath(), newMap);
+ return newMap.isEmpty() ? new ServiceConfigURL(url.getProtocol(), url.getUsername(), url.getPassword(), url.getHost(), url.getPort(), url.getPath(), (Map<String, String>) null)
+ : new ServiceConfigURL(url.getProtocol(), url.getUsername(), url.getPassword(), url.getHost(), url.getPort(), url.getPath(), newMap);
}
public static String encode(String value) {
@@ -436,92 +311,94 @@ class URL implements Serializable {
return address;
}
+ public URLAddress getUrlAddress() {
+ return urlAddress;
+ }
+
+ public URLParam getUrlParam() {
+ return urlParam;
+ }
+
public String getProtocol() {
- return protocol;
+ return urlAddress == null ? null : urlAddress.getProtocol();
}
public URL setProtocol(String protocol) {
- return new URL(protocol, username, password, host, port, path, getParameters());
+ URLAddress newURLAddress = urlAddress.setProtocol(protocol);
+ return returnURL(newURLAddress);
}
public String getUsername() {
- return username;
+ return urlAddress == null ? null : urlAddress.getUsername();
}
public URL setUsername(String username) {
- return new URL(getProtocol(), username, password, host, port, path, getParameters());
+ URLAddress newURLAddress = urlAddress.setUsername(username);
+ return returnURL(newURLAddress);
}
public String getPassword() {
- return password;
+ return urlAddress == null ? null : urlAddress.getPassword();
}
public URL setPassword(String password) {
- return new URL(getProtocol(), username, password, host, port, path, getParameters());
+ URLAddress newURLAddress = urlAddress.setPassword(password);
+ return returnURL(newURLAddress);
}
public String getAuthority() {
- if (StringUtils.isEmpty(username)
- && StringUtils.isEmpty(password)) {
+ if (StringUtils.isEmpty(getUsername())
+ && StringUtils.isEmpty(getPassword())) {
return null;
}
- return (username == null ? "" : username)
- + ":" + (password == null ? "" : password);
+ return (getUsername() == null ? "" : getUsername())
+ + ":" + (getPassword() == null ? "" : getPassword());
}
public String getHost() {
- return host;
+ return urlAddress == null ? null : urlAddress.getHost();
}
public URL setHost(String host) {
- return new URL(getProtocol(), username, password, host, port, path, getParameters());
+ URLAddress newURLAddress = urlAddress.setHost(host);
+ return returnURL(newURLAddress);
}
- /**
- * Fetch IP address for this URL.
- * <p>
- * Pls. note that IP should be used instead of Host when to compare with socket's address or to search in a map
- * which use address as its key.
- *
- * @return ip in string format
- */
- public String getIp() {
- if (ip == null) {
- ip = NetUtils.getIpByHost(host);
- }
- return ip;
- }
public int getPort() {
- return port;
+ return urlAddress == null ? 0 : urlAddress.getPort();
}
public URL setPort(int port) {
- return new URL(getProtocol(), username, password, host, port, path, getParameters());
+ URLAddress newURLAddress = urlAddress.setPort(port);
+ return returnURL(newURLAddress);
}
public int getPort(int defaultPort) {
+ int port = getPort();
return port <= 0 ? defaultPort : port;
}
public String getAddress() {
- if (address == null) {
- address = getAddress(host, port);
- }
- return address;
+ return urlAddress.getAddress();
}
public URL setAddress(String address) {
int i = address.lastIndexOf(':');
String host;
- int port = this.port;
+ int port = this.getPort();
if (i >= 0) {
host = address.substring(0, i);
port = Integer.parseInt(address.substring(i + 1));
} else {
host = address;
}
- return new URL(getProtocol(), username, password, host, port, path, getParameters());
+ URLAddress newURLAddress = urlAddress.setAddress(host, port);
+ return returnURL(newURLAddress);
+ }
+
+ public String getIp() {
+ return urlAddress.getIp();
}
public String getBackupAddress() {
@@ -553,14 +430,16 @@ class URL implements Serializable {
}
public String getPath() {
- return path;
+ return urlAddress == null ? null : urlAddress.getPath();
}
public URL setPath(String path) {
- return new URL(getProtocol(), username, password, host, port, path, getParameters());
+ URLAddress newURLAddress = urlAddress.setPath(path);
+ return returnURL(newURLAddress);
}
public String getAbsolutePath() {
+ String path = getPath();
if (path != null && !path.startsWith("/")) {
return "/" + path;
}
@@ -568,7 +447,7 @@ class URL implements Serializable {
}
public Map<String, String> getParameters() {
- return parameters;
+ return urlParam.getParameters();
}
/**
@@ -589,6 +468,41 @@ class URL implements Serializable {
return Collections.unmodifiableMap(selectedParameters);
}
+ public Map<String, Map<String, String>> getMethodParameters() {
+ return urlParam.getMethodParameters();
+ }
+
+ public String getParameterAndDecoded(String key) {
+ return getParameterAndDecoded(key, null);
+ }
+
+ public String getParameterAndDecoded(String key, String defaultValue) {
+ return decode(getParameter(key, defaultValue));
+ }
+
+ public String getParameter(String key) {
+ return urlParam.getParameter(key);
+ }
+
+ public String getParameter(String key, String defaultValue) {
+ String value = getParameter(key);
+ return StringUtils.isEmpty(value) ? defaultValue : value;
+ }
+
+ public String[] getParameter(String key, String[] defaultValue) {
+ String value = getParameter(key);
+ return StringUtils.isEmpty(value) ? defaultValue : COMMA_SPLIT_PATTERN.split(value);
+ }
+
+ public List<String> getParameter(String key, List<String> defaultValue) {
+ String value = getParameter(key);
+ if (StringUtils.isEmpty(value)) {
+ return defaultValue;
+ }
+ String[] strArray = COMMA_SPLIT_PATTERN.split(value);
+ return Arrays.asList(strArray);
+ }
+
/**
* Get parameter
*
@@ -624,42 +538,6 @@ class URL implements Serializable {
return result;
}
-
- public Map<String, Map<String, String>> getMethodParameters() {
- return methodParameters;
- }
-
- public String getParameterAndDecoded(String key) {
- return getParameterAndDecoded(key, null);
- }
-
- public String getParameterAndDecoded(String key, String defaultValue) {
- return decode(getParameter(key, defaultValue));
- }
-
- public String getParameter(String key) {
- return parameters.get(key);
- }
-
- public String getParameter(String key, String defaultValue) {
- String value = getParameter(key);
- return StringUtils.isEmpty(value) ? defaultValue : value;
- }
-
- public String[] getParameter(String key, String[] defaultValue) {
- String value = getParameter(key);
- return StringUtils.isEmpty(value) ? defaultValue : COMMA_SPLIT_PATTERN.split(value);
- }
-
- public List<String> getParameter(String key, List<String> defaultValue) {
- String value = getParameter(key);
- if (StringUtils.isEmpty(value)) {
- return defaultValue;
- }
- String[] strArray = COMMA_SPLIT_PATTERN.split(value);
- return Arrays.asList(strArray);
- }
-
protected Map<String, Number> getNumbers() {
// concurrent initialization is tolerant
if (numbers == null) {
@@ -852,24 +730,24 @@ class URL implements Serializable {
return URL.decode(getMethodParameter(method, key, defaultValue));
}
- public String getMethodParameterStrict(String method, String key) {
+ public String getMethodParameter(String method, String key) {
Map<String, String> keyMap = getMethodParameters().get(method);
String value = null;
if (keyMap != null) {
value = keyMap.get(key);
}
+ if (StringUtils.isEmpty(value)) {
+ value = urlParam.getParameter(key);
+ }
return value;
}
- public String getMethodParameter(String method, String key) {
+ public String getMethodParameterStrict(String method, String key) {
Map<String, String> keyMap = getMethodParameters().get(method);
String value = null;
if (keyMap != null) {
value = keyMap.get(key);
}
- if (StringUtils.isEmpty(value)) {
- value = parameters.get(key);
- }
return value;
}
@@ -1036,7 +914,7 @@ class URL implements Serializable {
public boolean hasMethodParameter(String method, String key) {
if (method == null) {
String suffix = "." + key;
- for (String fullKey : parameters.keySet()) {
+ for (String fullKey : getParameters().keySet()) {
if (fullKey.endsWith(suffix)) {
return true;
}
@@ -1045,7 +923,7 @@ class URL implements Serializable {
}
if (key == null) {
String prefix = method + ".";
- for (String fullKey : parameters.keySet()) {
+ for (String fullKey : getParameters().keySet()) {
if (fullKey.startsWith(prefix)) {
return true;
}
@@ -1056,6 +934,16 @@ class URL implements Serializable {
return StringUtils.isNotEmpty(value);
}
+ public String getAnyMethodParameter(String key) {
+ String suffix = "." + key;
+ for (String fullKey : getUrlParam().getParameters().keySet()) {
+ if (fullKey.endsWith(suffix)) {
+ return getUrlParam().getParameters().get(fullKey);
+ }
+ }
+ return null;
+ }
+
public boolean hasMethodParameter(String method) {
if (method == null) {
return false;
@@ -1064,11 +952,11 @@ class URL implements Serializable {
}
public boolean isLocalHost() {
- return NetUtils.isLocalHost(host) || getParameter(LOCALHOST_KEY, false);
+ return NetUtils.isLocalHost(getHost()) || getParameter(LOCALHOST_KEY, false);
}
public boolean isAnyHost() {
- return ANYHOST_VALUE.equals(host) || getParameter(ANYHOST_KEY, false);
+ return ANYHOST_VALUE.equals(getHost()) || getParameter(ANYHOST_KEY, false);
}
public URL addParameterAndEncoded(String key, String value) {
@@ -1132,66 +1020,13 @@ class URL implements Serializable {
}
public URL addParameter(String key, String value) {
- if (StringUtils.isEmpty(key)
- || StringUtils.isEmpty(value)) {
- return this;
- }
- // if value doesn't change, return immediately
- if (value.equals(getParameters().get(key))) { // value != null
- return this;
- }
-
- Map<String, String> map = new HashMap<>(getParameters());
- map.put(key, value);
-
- return new URL(getProtocol(), username, password, host, port, path, map);
+ URLParam newParam = urlParam.addParameter(key, value);
+ return returnURL(newParam);
}
public URL addParameterIfAbsent(String key, String value) {
- if (StringUtils.isEmpty(key)
- || StringUtils.isEmpty(value)) {
- return this;
- }
- if (hasParameter(key)) {
- return this;
- }
- Map<String, String> map = new HashMap<>(getParameters());
- map.put(key, value);
-
- return new URL(getProtocol(), username, password, host, port, path, map);
- }
-
- public URL addMethodParameter(String method, String key, String value) {
- if (StringUtils.isEmpty(method)
- || StringUtils.isEmpty(key)
- || StringUtils.isEmpty(value)) {
- return this;
- }
-
- Map<String, String> map = new HashMap<>(getParameters());
- map.put(method + "." + key, value);
- Map<String, Map<String, String>> methodMap = toMethodParameters(map);
- URL.putMethodParameter(method, key, value, methodMap);
-
- return new URL(getProtocol(), username, password, host, port, path, map, methodMap);
- }
-
- public URL addMethodParameterIfAbsent(String method, String key, String value) {
- if (StringUtils.isEmpty(method)
- || StringUtils.isEmpty(key)
- || StringUtils.isEmpty(value)) {
- return this;
- }
- if (hasMethodParameter(method, key)) {
- return this;
- }
-
- Map<String, String> map = new HashMap<>(getParameters());
- map.put(method + "." + key, value);
- Map<String, Map<String, String>> methodMap = toMethodParameters(map);
- URL.putMethodParameter(method, key, value, methodMap);
-
- return new URL(getProtocol(), username, password, host, port, path, map, methodMap);
+ URLParam newParam = urlParam.addParameterIfAbsent(key, value);
+ return returnURL(newParam);
}
/**
@@ -1201,42 +1036,13 @@ class URL implements Serializable {
* @return A new URL
*/
public URL addParameters(Map<String, String> parameters) {
- if (CollectionUtils.isEmptyMap(parameters)) {
- return this;
- }
-
- boolean hasAndEqual = true;
- for (Map.Entry<String, String> entry : parameters.entrySet()) {
- String value = getParameters().get(entry.getKey());
- if (value == null) {
- if (entry.getValue() != null) {
- hasAndEqual = false;
- break;
- }
- } else {
- if (!value.equals(entry.getValue())) {
- hasAndEqual = false;
- break;
- }
- }
- }
- // return immediately if there's no change
- if (hasAndEqual) {
- return this;
- }
-
- Map<String, String> map = new HashMap<>(getParameters());
- map.putAll(parameters);
- return new URL(getProtocol(), username, password, host, port, path, map);
+ URLParam newParam = urlParam.addParameters(parameters);
+ return returnURL(newParam);
}
public URL addParametersIfAbsent(Map<String, String> parameters) {
- if (CollectionUtils.isEmptyMap(parameters)) {
- return this;
- }
- Map<String, String> map = new HashMap<>(parameters);
- map.putAll(getParameters());
- return new URL(getProtocol(), username, password, host, port, path, map);
+ URLParam newURLParam = urlParam.addParametersIfAbsent(parameters);
+ return returnURL(newURLParam);
}
public URL addParameters(String... pairs) {
@@ -1244,7 +1050,7 @@ class URL implements Serializable {
return this;
}
if (pairs.length % 2 != 0) {
- throw new IllegalArgumentException("Map pairs can not be odd number.");
+ throw new IllegalArgumentException("Map pairs can not be odd numrer.");
}
Map<String, String> map = new HashMap<>();
int len = pairs.length / 2;
@@ -1276,74 +1082,63 @@ class URL implements Serializable {
}
public URL removeParameters(String... keys) {
- if (keys == null || keys.length == 0) {
- return this;
- }
- Map<String, String> map = new HashMap<>(getParameters());
- for (String key : keys) {
- map.remove(key);
- }
- if (map.size() == getParameters().size()) {
- return this;
- }
- return new URL(getProtocol(), username, password, host, port, path, map);
+ URLParam newURLParam = urlParam.removeParameters(keys);
+ return returnURL(newURLParam);
}
public URL clearParameters() {
- return new URL(getProtocol(), username, password, host, port, path, new HashMap<>());
+ URLParam newURLParam = urlParam.clearParameters();
+ return returnURL(newURLParam);
}
public String getRawParameter(String key) {
if (PROTOCOL_KEY.equals(key)) {
- return protocol;
+ return urlAddress.getProtocol();
}
if (USERNAME_KEY.equals(key)) {
- return username;
+ return urlAddress.getUsername();
}
if (PASSWORD_KEY.equals(key)) {
- return password;
+ return urlAddress.getPassword();
}
if (HOST_KEY.equals(key)) {
- return host;
+ return urlAddress.getHost();
}
if (PORT_KEY.equals(key)) {
- return String.valueOf(port);
+ return String.valueOf(urlAddress.getPort());
}
if (PATH_KEY.equals(key)) {
- return path;
+ return urlAddress.getPath();
}
- return getParameter(key);
+ return urlParam.getParameter(key);
}
public Map<String, String> toMap() {
- Map<String, String> map = new HashMap<>(parameters);
- if (protocol != null) {
- map.put(PROTOCOL_KEY, protocol);
+ Map<String, String> map = new HashMap<>(getParameters());
+ if (getProtocol() != null) {
+ map.put(PROTOCOL_KEY, getProtocol());
}
- if (username != null) {
- map.put(USERNAME_KEY, username);
+ if (getUsername() != null) {
+ map.put(USERNAME_KEY, getUsername());
}
- if (password != null) {
- map.put(PASSWORD_KEY, password);
+ if (getPassword() != null) {
+ map.put(PASSWORD_KEY, getPassword());
}
- if (host != null) {
- map.put(HOST_KEY, host);
+ if (getHost() != null) {
+ map.put(HOST_KEY, getHost());
}
- if (port > 0) {
- map.put(PORT_KEY, String.valueOf(port));
+ if (getPort() > 0) {
+ map.put(PORT_KEY, String.valueOf(getPort()));
}
- if (path != null) {
- map.put(PATH_KEY, path);
+ if (getPath() != null) {
+ map.put(PATH_KEY, getPath());
}
return map;
}
@Override
public String toString() {
- if (string != null) {
- return string;
- }
- return string = buildString(false, true); // no show username and password
+ return buildString(false, true); // no show username and password
}
public String toString(String... parameters) {
@@ -1351,10 +1146,7 @@ class URL implements Serializable {
}
public String toIdentityString() {
- if (identity != null) {
- return identity;
- }
- return identity = buildString(true, false); // only return identity message, see the method "equals" and "hashCode"
+ return buildString(true, false); // only return identity message, see the method "equals" and "hashCode"
}
public String toIdentityString(String... parameters) {
@@ -1362,10 +1154,7 @@ class URL implements Serializable {
}
public String toFullString() {
- if (full != null) {
- return full;
- }
- return full = buildString(true, true);
+ return buildString(true, true);
}
public String toFullString(String... parameters) {
@@ -1373,10 +1162,7 @@ class URL implements Serializable {
}
public String toParameterString() {
- if (parameter != null) {
- return parameter;
- }
- return parameter = toParameterString(new String[0]);
+ return toParameterString(new String[0]);
}
public String toParameterString(String... parameters) {
@@ -1385,7 +1171,7 @@ class URL implements Serializable {
return buf.toString();
}
- private void buildParameters(StringBuilder buf, boolean concat, String[] parameters) {
+ protected void buildParameters(StringBuilder buf, boolean concat, String[] parameters) {
if (CollectionUtils.isNotEmptyMap(getParameters())) {
List<String> includes = (ArrayUtils.isEmpty(parameters) ? null : Arrays.asList(parameters));
boolean first = true;
@@ -1414,29 +1200,29 @@ class URL implements Serializable {
private String buildString(boolean appendUser, boolean appendParameter, boolean useIP, boolean useService, String... parameters) {
StringBuilder buf = new StringBuilder();
- if (StringUtils.isNotEmpty(protocol)) {
- buf.append(protocol);
+ if (StringUtils.isNotEmpty(getProtocol())) {
+ buf.append(getProtocol());
buf.append("://");
}
- if (appendUser && StringUtils.isNotEmpty(username)) {
- buf.append(username);
- if (StringUtils.isNotEmpty(password)) {
+ if (appendUser && StringUtils.isNotEmpty(getUsername())) {
+ buf.append(getUsername());
+ if (StringUtils.isNotEmpty(getPassword())) {
buf.append(":");
- buf.append(password);
+ buf.append(getPassword());
}
buf.append("@");
}
String host;
if (useIP) {
- host = getIp();
+ host = urlAddress.getIp();
} else {
host = getHost();
}
if (StringUtils.isNotEmpty(host)) {
buf.append(host);
- if (port > 0) {
+ if (getPort() > 0) {
buf.append(":");
- buf.append(port);
+ buf.append(getPort());
}
}
String path;
@@ -1465,7 +1251,7 @@ class URL implements Serializable {
}
public InetSocketAddress toInetSocketAddress() {
- return new InetSocketAddress(host, port);
+ return new InetSocketAddress(getHost(), getPort());
}
/**
@@ -1506,7 +1292,7 @@ class URL implements Serializable {
if (inf == null) {
return null;
}
- serviceKey = buildKey(inf, getParameter(GROUP_KEY), getParameter(VERSION_KEY));
+ serviceKey = buildKey(inf, getGroup(), getVersion());
return serviceKey;
}
@@ -1516,11 +1302,11 @@ class URL implements Serializable {
* @return
*/
public String getPathKey() {
- String inf = StringUtils.isNotEmpty(path) ? path : getServiceInterface();
+ String inf = StringUtils.isNotEmpty(getPath()) ? getPath() : getServiceInterface();
if (inf == null) {
return null;
}
- return buildKey(inf, getParameter(GROUP_KEY), getParameter(VERSION_KEY));
+ return buildKey(inf, getGroup(), getVersion());
}
public static String buildKey(String path, String group, String version) {
@@ -1549,7 +1335,7 @@ class URL implements Serializable {
}
public String getServiceInterface() {
- return getParameter(INTERFACE_KEY, path);
+ return getParameter(INTERFACE_KEY, getPath());
}
public URL setServiceInterface(String service) {
@@ -1648,22 +1434,13 @@ class URL implements Serializable {
public Configuration toConfiguration() {
InmemoryConfiguration configuration = new InmemoryConfiguration();
- configuration.addProperties(parameters);
+ configuration.addProperties(getParameters());
return configuration;
}
@Override
public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((host == null) ? 0 : host.hashCode());
- result = prime * result + ((parameters == null) ? 0 : parameters.hashCode());
- result = prime * result + ((password == null) ? 0 : password.hashCode());
- result = prime * result + ((path == null) ? 0 : path.hashCode());
- result = prime * result + port;
- result = prime * result + ((protocol == null) ? 0 : protocol.hashCode());
- result = prime * result + ((username == null) ? 0 : username.hashCode());
- return result;
+ return Objects.hash(urlAddress, urlParam);
}
@Override
@@ -1674,36 +1451,11 @@ class URL implements Serializable {
if (obj == null) {
return false;
}
- if (getClass() != obj.getClass()) {
+ if (!(obj instanceof URL)) {
return false;
}
URL other = (URL) obj;
- if (!StringUtils.isEquals(host, other.host)) {
- return false;
- }
- if (parameters == null) {
- if (other.parameters != null) {
- return false;
- }
- } else if (!parameters.equals(other.parameters)) {
- return false;
- }
- if (!StringUtils.isEquals(password, other.password)) {
- return false;
- }
- if (!StringUtils.isEquals(path, other.path)) {
- return false;
- }
- if (port != other.port) {
- return false;
- }
- if (!StringUtils.isEquals(protocol, other.protocol)) {
- return false;
- }
- if (!StringUtils.isEquals(username, other.username)) {
- return false;
- }
- return true;
+ return Objects.equals(this.getUrlAddress(), other.getUrlAddress()) && Objects.equals(this.getUrlParam(), other.getUrlParam());
}
public static void putMethodParameter(String method, String key, String value, Map<String, Map<String, String>> methodParameters) {
@@ -1711,6 +1463,114 @@ class URL implements Serializable {
subParameter.put(key, value);
}
+ protected <T extends URL> T newURL(URLAddress urlAddress, URLParam urlParam) {
+ return (T) new ServiceConfigURL(urlAddress, urlParam, null);
+ }
+
+ /* methods introduced for CompositeURL, CompositeURL must override to make the implementations meaningful */
+
+ public String getApplication(String defaultValue) {
+ String value = getApplication();
+ return StringUtils.isEmpty(value) ? defaultValue : value;
+ }
+
+ public String getApplication() {
+ return getParameter(APPLICATION_KEY);
+ }
+
+ public String getRemoteApplication() {
+ return getParameter(REMOTE_APPLICATION_KEY);
+ }
+
+ public String getGroup() {
+ return getParameter(GROUP_KEY);
+ }
+
+ public String getGroup(String defaultValue) {
+ String value = getGroup();
+ return StringUtils.isEmpty(value) ? defaultValue : value;
+ }
+
+ public String getVersion() {
+ return getParameter(VERSION_KEY);
+ }
+
+ public String getVersion(String defaultValue) {
+ String value = getVersion();
+ return StringUtils.isEmpty(value) ? defaultValue : value;
+ }
+
+ public String getConcatenatedParameter(String key) {
+ return getParameter(key);
+ }
+
+ public String getCategory(String defaultValue) {
+ String value = getCategory();
+ if (StringUtils.isEmpty(value)) {
+ value = defaultValue;
+ }
+ return value;
+ }
+
+ public String[] getCategory(String[] defaultValue) {
+ String value = getCategory();
+ return StringUtils.isEmpty(value) ? defaultValue : COMMA_SPLIT_PATTERN.split(value);
+ }
+
+ public String getCategory() {
+ return getParameter(CATEGORY_KEY);
+ }
+
+ public String getSide(String defaultValue) {
+ String value = getSide();
+ return StringUtils.isEmpty(value) ? defaultValue : value;
+ }
+
+ public String getSide() {
+ return getParameter(SIDE_KEY);
+ }
+
+ /* Service Config URL, START*/
+ public Map<String, Object> getAttributes() {
+ return new HashMap<>();
+ }
+
+ public URL addAttributes(Map<String, Object> attributes) {
+ return this;
+ }
+
+ public Object getAttribute(String key) {
+ return null;
+ }
+
+ public URL putAttribute(String key, Object obj) {
+ return this;
+ }
+
+ public URL removeAttribute(String key) {
+ return this;
+ }
+
+ public boolean hasAttribute(String key) {
+ return true;
+ }
+
+ /* Service Config URL, END*/
+
+ private URL returnURL(URLAddress newURLAddress) {
+ if (urlAddress == newURLAddress) {
+ return this;
+ }
+ return newURL(newURLAddress, urlParam);
+ }
+
+ private URL returnURL(URLParam newURLParam) {
+ if (urlParam == newURLParam) {
+ return this;
+ }
+ return newURL(urlAddress, newURLParam);
+ }
+
/* add service scope operations, see InstanceAddressURL */
public Map<String, String> getServiceParameters(String service) {
return getParameters();
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/URLBuilder.java b/dubbo-common/src/main/java/org/apache/dubbo/common/URLBuilder.java
index 20c6c60..7ab8bb3 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/URLBuilder.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/URLBuilder.java
@@ -16,6 +16,7 @@
*/
package org.apache.dubbo.common;
+import org.apache.dubbo.common.url.component.ServiceConfigURL;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.StringUtils;
@@ -24,7 +25,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
-public final class URLBuilder {
+public final class URLBuilder extends ServiceConfigURL {
private String protocol;
private String username;
@@ -41,6 +42,8 @@ public final class URLBuilder {
private Map<String, String> parameters;
+ private Map<String, Object> attributes;
+
private Map<String, Map<String, String>> methodParameters;
public URLBuilder() {
@@ -51,6 +54,7 @@ public final class URLBuilder {
port = 0;
path = null;
parameters = new HashMap<>();
+ attributes = new HashMap<>();
methodParameters = new HashMap<>();
}
@@ -83,8 +87,9 @@ public final class URLBuilder {
String password,
String host,
int port,
- String path, Map<String, String> parameters) {
- this(protocol, username, password, host, port, path, parameters, URL.toMethodParameters(parameters));
+ String path,
+ Map<String, String> parameters) {
+ this(protocol, username, password, host, port, path, parameters, null);
}
public URLBuilder(String protocol,
@@ -92,8 +97,9 @@ public final class URLBuilder {
String password,
String host,
int port,
- String path, Map<String, String> parameters,
- Map<String, Map<String, String>> methodParameters) {
+ String path,
+ Map<String, String> parameters,
+ Map<String, Object> attributes) {
this.protocol = protocol;
this.username = username;
this.password = password;
@@ -101,7 +107,7 @@ public final class URLBuilder {
this.port = port;
this.path = path;
this.parameters = parameters != null ? parameters : new HashMap<>();
- this.methodParameters = (methodParameters != null ? methodParameters : new HashMap<>());
+ this.attributes = attributes != null ? attributes : new HashMap<>();
}
public static URLBuilder from(URL url) {
@@ -112,7 +118,7 @@ public final class URLBuilder {
int port = url.getPort();
String path = url.getPath();
Map<String, String> parameters = new HashMap<>(url.getParameters());
- Map<String, Map<String, String>> methodParameters = new HashMap<>(url.getMethodParameters());
+ Map<String, Object> attributes = new HashMap<>(url.getAttributes());
return new URLBuilder(
protocol,
username,
@@ -121,14 +127,14 @@ public final class URLBuilder {
port,
path,
parameters,
- methodParameters);
+ attributes);
}
- public URL build() {
+ public ServiceConfigURL build() {
if (StringUtils.isEmpty(username) && StringUtils.isNotEmpty(password)) {
throw new IllegalArgumentException("Invalid url, password without username!");
}
- port = port < 0 ? 0 : port;
+ port = Math.max(port, 0);
// trim the leading "/"
int firstNonSlash = 0;
if (path != null) {
@@ -141,13 +147,14 @@ public final class URLBuilder {
path = path.substring(firstNonSlash);
}
}
- if (CollectionUtils.isEmptyMap(methodParameters)) {
- return new URL(protocol, username, password, host, port, path, parameters);
- } else {
- return new URL(protocol, username, password, host, port, path, parameters, methodParameters);
- }
+ return new ServiceConfigURL(protocol, username, password, host, port, path, parameters, attributes);
}
+ @Override
+ public URLBuilder putAttribute(String key, Object obj) {
+ attributes.put(key, obj);
+ return this;
+ }
public URLBuilder setProtocol(String protocol) {
this.protocol = protocol;
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/URLStrParser.java b/dubbo-common/src/main/java/org/apache/dubbo/common/URLStrParser.java
index 37afb78..619b1bb 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/URLStrParser.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/URLStrParser.java
@@ -16,16 +16,26 @@
*/
package org.apache.dubbo.common;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.url.component.ServiceConfigURL;
+import org.apache.dubbo.common.url.component.URLItemCache;
+
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
import static org.apache.dubbo.common.utils.StringUtils.EMPTY_STRING;
import static org.apache.dubbo.common.utils.StringUtils.decodeHexByte;
import static org.apache.dubbo.common.utils.Utf8Utils.decodeUtf8;
public final class URLStrParser {
-
+ private static final Logger logger = LoggerFactory.getLogger(URLStrParser.class);
+ public static final String ENCODED_QUESTION_MARK = "%3F";
+ public static final String ENCODED_TIMESTAMP_KEY = "timestamp%3D";
+ public static final String ENCODED_PID_KEY = "pid%3D";
+ public static final String ENCODED_AND_MARK = "%26";
private static final char SPACE = 0x20;
private static final ThreadLocal<TempBuf> DECODE_TEMP_BUF = ThreadLocal.withInitial(() -> new TempBuf(1024));
@@ -34,12 +44,16 @@ public final class URLStrParser {
//empty
}
+ public static URL parseDecodedStr(String decodedURLStr) {
+ return parseDecodedStr(decodedURLStr, false);
+ }
+
/**
* @param decodedURLStr : after {@link URL#decode} string
* decodedURLStr format: protocol://username:password@host:port/path?k1=v1&k2=v2
* [protocol://][username:password@][host:port]/[path][?k1=v1&k2=v2]
*/
- public static URL parseDecodedStr(String decodedURLStr) {
+ public static URL parseDecodedStr(String decodedURLStr, boolean modifiable) {
Map<String, String> parameters = null;
int pathEndIdx = decodedURLStr.indexOf('?');
if (pathEndIdx >= 0) {
@@ -49,7 +63,7 @@ public final class URLStrParser {
}
String decodedBody = decodedURLStr.substring(0, pathEndIdx);
- return parseURLBody(decodedURLStr, decodedBody, parameters);
+ return parseURLBody(decodedURLStr, decodedBody, parameters, modifiable);
}
private static Map<String, String> parseDecodedParams(String str, int from) {
@@ -92,7 +106,7 @@ public final class URLStrParser {
* @param parameters :
* @return URL
*/
- private static URL parseURLBody(String fullURLStr, String decodedBody, Map<String, String> parameters) {
+ private static URL parseURLBody(String fullURLStr, String decodedBody, Map<String, String> parameters, boolean modifiable) {
int starIdx = 0, endIdx = decodedBody.length();
String protocol = null;
int protoEndIdx = decodedBody.indexOf("://");
@@ -125,9 +139,13 @@ public final class URLStrParser {
String password = null;
int pwdEndIdx = lastIndexOf(decodedBody, '@', starIdx, endIdx);
if (pwdEndIdx > 0) {
- int userNameEndIdx = indexOf(decodedBody, ':', starIdx, pwdEndIdx);
- username = decodedBody.substring(starIdx, userNameEndIdx);
- password = decodedBody.substring(userNameEndIdx + 1, pwdEndIdx);
+ int passwordStartIdx = indexOf(decodedBody, ':', starIdx, pwdEndIdx);
+ if (passwordStartIdx != -1) {//tolerate incomplete user pwd input, like '1234@'
+ username = decodedBody.substring(starIdx, passwordStartIdx);
+ password = decodedBody.substring(passwordStartIdx + 1, pwdEndIdx);
+ } else {
+ username = decodedBody.substring(starIdx, pwdEndIdx);
+ }
starIdx = pwdEndIdx + 1;
}
@@ -149,7 +167,44 @@ public final class URLStrParser {
if (endIdx > starIdx) {
host = decodedBody.substring(starIdx, endIdx);
}
- return new URL(protocol, username, password, host, port, path, parameters);
+
+ // check cache
+ protocol = URLItemCache.checkProtocol(protocol);
+ path = URLItemCache.checkPath(path);
+
+ return new ServiceConfigURL(protocol, username, password, host, port, path, parameters);
+ }
+
+ public static URL parseEncodedStr(String encodedURLStr) {
+ return parseEncodedStr(encodedURLStr, false);
+ }
+
+ public static String[] parseRawURLToArrays(String rawURLStr, int pathEndIdx) {
+ String[] parts = new String[2];
+ int paramStartIdx = pathEndIdx + 3;//skip ENCODED_QUESTION_MARK
+ if (pathEndIdx == -1) {
+ pathEndIdx = rawURLStr.indexOf('?');
+ if (pathEndIdx == -1) {
+ // url with no params, decode anyway
+ rawURLStr = URL.decode(rawURLStr);
+ } else {
+ paramStartIdx = pathEndIdx + 1;
+ }
+ }
+ if (pathEndIdx >= 0) {
+ parts[0] = rawURLStr.substring(0, pathEndIdx);
+ parts[1] = rawURLStr.substring(paramStartIdx);
+ } else {
+ parts = new String[]{rawURLStr};
+ }
+ return parts;
+ }
+
+ public static Map<String, String> parseParams(String rawParams, boolean encoded) {
+ if (encoded) {
+ return parseEncodedParams(rawParams, 0);
+ }
+ return parseDecodedParams(rawParams, 0);
}
/**
@@ -157,7 +212,7 @@ public final class URLStrParser {
* encodedURLStr after decode format: protocol://username:password@host:port/path?k1=v1&k2=v2
* [protocol://][username:password@][host:port]/[path][?k1=v1&k2=v2]
*/
- public static URL parseEncodedStr(String encodedURLStr) {
+ public static URL parseEncodedStr(String encodedURLStr, boolean modifiable) {
Map<String, String> parameters = null;
int pathEndIdx = encodedURLStr.indexOf("%3F");// '?'
if (pathEndIdx >= 0) {
@@ -168,7 +223,7 @@ public final class URLStrParser {
//decodedBody format: [protocol://][username:password@][host:port]/[path]
String decodedBody = decodeComponent(encodedURLStr, 0, pathEndIdx, false, DECODE_TEMP_BUF.get());
- return parseURLBody(encodedURLStr, decodedBody, parameters);
+ return parseURLBody(encodedURLStr, decodedBody, parameters, modifiable);
}
private static Map<String, String> parseEncodedParams(String str, int from) {
@@ -225,12 +280,30 @@ public final class URLStrParser {
if (isEncoded) {
String name = decodeComponent(str, nameStart, valueStart - 3, false, tempBuf);
- String value = decodeComponent(str, valueStart, valueEnd, false, tempBuf);
- params.put(name, value);
+ String value;
+ if (valueStart == valueEnd) {
+ value = name;
+ } else {
+ value = decodeComponent(str, valueStart, valueEnd, false, tempBuf);
+ }
+ URLItemCache.putParams(params,name, value);
+ // compatible with lower versions registering "default." keys
+ if (name.startsWith(DEFAULT_KEY_PREFIX)) {
+ params.putIfAbsent(name.substring(DEFAULT_KEY_PREFIX.length()), value);
+ }
} else {
- String name = str.substring(nameStart, valueStart -1);
- String value = str.substring(valueStart, valueEnd);
- params.put(name, value);
+ String name = str.substring(nameStart, valueStart - 1);
+ String value;
+ if (valueStart == valueEnd) {
+ value = name;
+ } else {
+ value = str.substring(valueStart, valueEnd);
+ }
+ URLItemCache.putParams(params, name, value);
+ // compatible with lower versions registering "default." keys
+ if (name.startsWith(DEFAULT_KEY_PREFIX)) {
+ params.putIfAbsent(name.substring(DEFAULT_KEY_PREFIX.length()), value);
+ }
}
return true;
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java
index 37f5e82..ea4b4e5 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java
@@ -20,6 +20,8 @@ import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
import org.apache.dubbo.common.context.FrameworkExt;
import org.apache.dubbo.common.context.LifecycleAdapter;
import org.apache.dubbo.common.extension.DisableInject;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.config.AbstractConfig;
import org.apache.dubbo.config.ConfigCenterConfig;
import org.apache.dubbo.config.context.ConfigConfigurationAdapter;
@@ -32,6 +34,8 @@ import java.util.Map;
import java.util.Optional;
public class Environment extends LifecycleAdapter implements FrameworkExt {
+ private static final Logger logger = LoggerFactory.getLogger(Environment.class);
+
public static final String NAME = "environment";
private final PropertiesConfiguration propertiesConfiguration;
@@ -160,7 +164,10 @@ public class Environment extends LifecycleAdapter implements FrameworkExt {
public Configuration getDynamicGlobalConfiguration() {
if (dynamicGlobalConfiguration == null) {
if (dynamicConfiguration == null) {
- throw new IllegalStateException("Init dynamic configuration before use.");
+ if (logger.isWarnEnabled()) {
+ logger.warn("dynamicConfiguration is null , return globalConfiguration.");
+ }
+ return globalConfiguration;
}
dynamicGlobalConfiguration = new CompositeConfiguration();
dynamicGlobalConfiguration.addConfiguration(dynamicConfiguration);
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
index a9ac119..5bb4e5f 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
@@ -306,6 +306,12 @@ public interface CommonConstants {
String GENERIC_WITH_CLZ_KEY = "generic.include.class";
/**
+ * Whether to cache locally, default is true
+ */
+ String REGISTRY_LOCAL_FILE_CACHE_ENABLED = "file.cache";
+
+
+ /**
* The limit of callback service instances for one interface on every client
*/
String CALLBACK_INSTANCES_LIMIT_KEY = "callbacks";
@@ -355,4 +361,11 @@ public interface CommonConstants {
*/
String DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH = "META-INF/dubbo/service-name-mapping.properties";
+ String REGISTRY_DELAY_NOTIFICATION_KEY = "delay-notification";
+
+ String FILTER_BUILDER_KEY = "filter-builder";
+
+ String CACHE_CLEAR_TASK_INTERVAL = "dubbo.application.url.cache.task.interval";
+ String CACHE_CLEAR_WAITING_THRESHOLD = "dubbo.application.url.cache.clear.waiting";
+
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java
index 3419deb..f70304d 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java
@@ -45,6 +45,8 @@ public interface RegistryConstants {
String CONFIGURATORS_CATEGORY = "configurators";
+ String ALL_CATEGORIES = "providers,configurators,routers";
+
String DYNAMIC_CONFIGURATORS_CATEGORY = "dynamicconfigurators";
String APP_DYNAMIC_CONFIGURATORS_CATEGORY = "appdynamicconfigurators";
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
index 922b04a..8b88422 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
@@ -334,13 +334,12 @@ public class ExtensionLoader<T> {
keyValue = arr[1];
}
- for (Map.Entry<String, String> entry : url.getParameters().entrySet()) {
- String k = entry.getKey();
- String v = entry.getValue();
- if ((k.equals(key) || k.endsWith("." + key))
- && ((keyValue != null && keyValue.equals(v)) || (keyValue == null && ConfigUtils.isNotEmpty(v)))) {
- return true;
- }
+ String realValue = url.getParameter(key);
+ if (StringUtils.isEmpty(realValue)) {
+ realValue = url.getAnyMethodParameter(key);
+ }
+ if ((keyValue != null && keyValue.equals(realValue)) || (keyValue == null && ConfigUtils.isNotEmpty(realValue))) {
+ return true;
}
}
return false;
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/DefaultExecutorRepository.java b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/DefaultExecutorRepository.java
index d53236a..66eafca 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/DefaultExecutorRepository.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/DefaultExecutorRepository.java
@@ -33,7 +33,6 @@ import java.util.concurrent.ThreadPoolExecutor;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
import static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_SERVICE_COMPONENT_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;
/**
@@ -50,6 +49,8 @@ public class DefaultExecutorRepository implements ExecutorRepository {
private ScheduledExecutorService serviceExporterExecutor;
+ public ScheduledExecutorService registryNotificationExecutor;
+
private ScheduledExecutorService reconnectScheduledExecutor;
private ScheduledExecutorService serviceDiscveryAddressNotificationExecutor;
@@ -65,6 +66,7 @@ public class DefaultExecutorRepository implements ExecutorRepository {
// reconnectScheduledExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("Dubbo-reconnect-scheduler"));
serviceExporterExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Dubbo-exporter-scheduler"));
serviceDiscveryAddressNotificationExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("Dubbo-SD-address-refresh"));
+ registryNotificationExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("Dubbo-registry-notification"));
}
/**
@@ -75,7 +77,7 @@ public class DefaultExecutorRepository implements ExecutorRepository {
*/
public synchronized ExecutorService createExecutorIfAbsent(URL url) {
String componentKey = EXECUTOR_SERVICE_COMPONENT_KEY;
- if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {
+ if (CONSUMER_SIDE.equalsIgnoreCase(url.getSide())) {
componentKey = CONSUMER_SIDE;
}
Map<Integer, ExecutorService> executors = data.computeIfAbsent(componentKey, k -> new ConcurrentHashMap<>());
@@ -92,7 +94,7 @@ public class DefaultExecutorRepository implements ExecutorRepository {
public ExecutorService getExecutor(URL url) {
String componentKey = EXECUTOR_SERVICE_COMPONENT_KEY;
- if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {
+ if (CONSUMER_SIDE.equalsIgnoreCase(url.getSide())) {
componentKey = CONSUMER_SIDE;
}
Map<Integer, ExecutorService> executors = data.get(componentKey);
@@ -157,6 +159,11 @@ public class DefaultExecutorRepository implements ExecutorRepository {
return serviceExporterExecutor;
}
+ @Override
+ public ScheduledExecutorService getRegistryNotificationExecutor() {
+ return registryNotificationExecutor;
+ }
+
public ScheduledExecutorService getServiceDiscveryAddressNotificationExecutor() {
return serviceDiscveryAddressNotificationExecutor;
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/ExecutorRepository.java b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/ExecutorRepository.java
index 0f0211d..5c08fe3 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/ExecutorRepository.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/ExecutorRepository.java
@@ -60,6 +60,14 @@ public interface ExecutorRepository {
ScheduledExecutorService getServiceDiscveryAddressNotificationExecutor();
/**
+ * Scheduled executor handle registry notification.
+ *
+ * @return
+ */
+ ScheduledExecutorService getRegistryNotificationExecutor();
+
+
+ /**
* Get the default shared threadpool.
*
* @return
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/DubboServiceAddressURL.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/DubboServiceAddressURL.java
new file mode 100644
index 0000000..80cadc6
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/DubboServiceAddressURL.java
@@ -0,0 +1,143 @@
+/*
+ * 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.common.url.component;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.StringUtils;
+
+import java.util.Map;
+import java.util.Objects;
+
+import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
+
+public class DubboServiceAddressURL extends ServiceAddressURL {
+ public static DubboServiceAddressURL valueOf(String rawURL, URL consumerURL) {
+ return valueOf(rawURL, consumerURL, null);
+ }
+
+ public static DubboServiceAddressURL valueOf(String rawURL, URL consumerURL, ServiceConfigURL overriddenURL) {
+ URL url = valueOf(rawURL, true);
+ return new DubboServiceAddressURL(url.getUrlAddress(), url.getUrlParam(), consumerURL, overriddenURL);
+ }
+
+ private ServiceConfigURL overrideURL;
+
+ public DubboServiceAddressURL(URLAddress urlAddress, URLParam urlParam, URL consumerURL, ServiceConfigURL overrideURL) {
+ super(urlAddress, urlParam, consumerURL);
+ this.overrideURL = overrideURL;
+ }
+
+ protected <T extends URL> T newURL(URLAddress urlAddress, URLParam urlParam) {
+ return (T) new DubboServiceAddressURL(urlAddress, urlParam, this.consumerURL, this.overrideURL);
+ }
+
+ @Override
+ public String getSide() {
+ return consumerURL.getParameter(SIDE_KEY);
+ }
+
+ @Override
+ public String getParameter(String key) {
+ String value = null;
+ if (overrideURL != null) {
+ value = overrideURL.getParameter(key);
+ }
+ if (StringUtils.isEmpty(value)) {
+ value = super.getParameter(key);
+ }
+ return value;
+ }
+
+ @Override
+ public String getMethodParameter(String method, String key) {
+ String value = null;
+ if (overrideURL != null) {
+ value = overrideURL.getMethodParameterStrict(method, key);
+ }
+ if (StringUtils.isEmpty(value)) {
+ value = super.getMethodParameter(method, key);
+ }
+ return value;
+ }
+
+ @Override
+ public String getAnyMethodParameter(String key) {
+ String value = null;
+ if (overrideURL != null) {
+ value = overrideURL.getAnyMethodParameter(key);
+ }
+ if (StringUtils.isEmpty(value)) {
+ value = super.getAnyMethodParameter(key);
+ }
+ return value;
+ }
+
+ public ServiceConfigURL getOverrideURL() {
+ return overrideURL;
+ }
+
+ public void setOverrideURL(ServiceConfigURL overrideURL) {
+ this.overrideURL = overrideURL;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ return prime * super.hashCode() + (overrideURL == null ? 0 : overrideURL.hashCode());
+ }
+
+ /**
+ * ignore consumer url compare.
+ * It's only meaningful for comparing two AddressURLs related to the same consumerURL.
+ *
+ * @param obj
+ * @return
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof DubboServiceAddressURL)) {
+ return false;
+ }
+ if (overrideURL == null) {
+ return super.equals(obj);
+ } else {
+ DubboServiceAddressURL other = (DubboServiceAddressURL) obj;
+ boolean overrideEquals = Objects.equals(overrideURL.getParameters(), other.getOverrideURL().getParameters());
+ if (!overrideEquals) {
+ return false;
+ }
+
+ Map<String, String> params = this.getParameters();
+ for (Map.Entry<String, String> entry : params.entrySet()) {
+ String key = entry.getKey();
+ if (overrideURL.getParameters().containsKey(key)) {
+ continue;
+ }
+ if (!entry.getValue().equals(other.getUrlParam().getParameter(key))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/PathURLAddress.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/PathURLAddress.java
new file mode 100644
index 0000000..f723991
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/PathURLAddress.java
@@ -0,0 +1,175 @@
+/*
+ * 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.common.url.component;
+
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+
+import java.util.Objects;
+
+public class PathURLAddress extends URLAddress {
+ private String protocol;
+ private String username;
+ private String password;
+ private String path;
+
+ private transient String address;
+ private transient String ip;
+
+ public PathURLAddress(String protocol, String username, String password, String path, String host, int port) {
+ this(protocol, username, password, path, host, port, null);
+ }
+
+ public PathURLAddress(String protocol, String username, String password, String path, String host, int port, String rawAddress) {
+ super(host, port, rawAddress);
+
+ this.protocol = protocol;
+ this.username = username;
+ this.password = password;
+
+ // trim the beginning "/"
+ while (path != null && path.startsWith("/")) {
+ path = path.substring(1);
+ }
+ this.path = path;
+ }
+
+ public String getProtocol() {
+ return protocol;
+ }
+
+ public URLAddress setProtocol(String protocol) {
+ return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public URLAddress setUsername(String username) {
+ return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public PathURLAddress setPassword(String password) {
+ return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public PathURLAddress setPath(String path) {
+ return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);
+ }
+
+ @Override
+ public URLAddress setHost(String host) {
+ return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);
+ }
+
+ @Override
+ public URLAddress setPort(int port) {
+ return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);
+ }
+
+ @Override
+ public URLAddress setAddress(String host, int port) {
+ return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);
+ }
+
+ public String getAddress() {
+ if (address == null) {
+ address = getAddress(getHost(), getPort());
+ }
+ return address;
+ }
+
+ /**
+ * Fetch IP address for this URL.
+ * <p>
+ * Pls. note that IP should be used instead of Host when to compare with socket's address or to search in a map
+ * which use address as its key.
+ *
+ * @return ip in string format
+ */
+ public String getIp() {
+ if (ip == null) {
+ ip = NetUtils.getIpByHost(getHost());
+ }
+ return ip;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(protocol, username, password, path, host, port);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (!(obj instanceof URLAddress)) return false;
+ URLAddress that = (URLAddress) obj;
+ return Objects.equals(this.getProtocol(), that.getProtocol()) &&
+ Objects.equals(this.getUsername(), that.getUsername()) &&
+ Objects.equals(this.getPassword(), that.getPassword()) &&
+ Objects.equals(this.getPath(), that.getPath()) &&
+ Objects.equals(this.getHost(), that.getHost()) &&
+ Objects.equals(this.getPort(), that.getPort());
+ }
+
+ @Override
+ public String toString() {
+ if (rawAddress != null) {
+ return rawAddress;
+ }
+
+ StringBuilder buf = new StringBuilder();
+ if (StringUtils.isNotEmpty(protocol)) {
+ buf.append(protocol);
+ buf.append("://");
+ }
+//
+// if (StringUtils.isNotEmpty(username)) {
+// buf.append(username);
+// if (StringUtils.isNotEmpty(password)) {
+// buf.append(":");
+// buf.append(password);
+// }
+// buf.append("@");
+// }
+
+ if (StringUtils.isNotEmpty(host)) {
+ buf.append(host);
+ if (port > 0) {
+ buf.append(":");
+ buf.append(port);
+ }
+ }
+
+ if (StringUtils.isNotEmpty(path)) {
+ buf.append("/");
+ buf.append(path);
+ }
+
+ return buf.toString();
+ }
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/ServiceAddressURL.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/ServiceAddressURL.java
new file mode 100644
index 0000000..91c8412
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/ServiceAddressURL.java
@@ -0,0 +1,218 @@
+/*
+ * 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.common.url.component;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.StringUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
+import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;
+
+public abstract class ServiceAddressURL extends URL {
+ protected final transient URL consumerURL;
+
+ //cache
+ private transient Map<String, String> concatenatedPrams;
+// private transient Map<String, String> allParameters;
+
+ public ServiceAddressURL(
+ String protocol,
+ String username,
+ String password,
+ String host,
+ int port,
+ String path,
+ Map<String, String> parameters,
+ URL consumerURL
+ ) {
+ super(protocol, username, password, host, port, path, parameters);
+ this.consumerURL = consumerURL;
+ }
+
+ public ServiceAddressURL(URLAddress urlAddress, URLParam urlParam, URL consumerURL){
+ super(urlAddress, urlParam);
+ this.consumerURL = consumerURL;
+ }
+
+ @Override
+ public String getPath() {
+ return consumerURL.getPath();
+ }
+
+ @Override
+ public String getServiceInterface() {
+ return consumerURL.getServiceInterface();
+ }
+
+ @Override
+ public String getApplication() {
+ return consumerURL.getApplication();
+ }
+
+ @Override
+ public String getRemoteApplication() {
+ return super.getParameter(APPLICATION_KEY);
+ }
+
+ @Override
+ public String getGroup() {
+ String group = super.getParameter(GROUP_KEY);
+ if (StringUtils.isNotEmpty(group)) {
+ return group;
+ }
+ return consumerURL.getGroup();
+ }
+
+ @Override
+ public String getVersion() {
+ String version = super.getParameter(VERSION_KEY);
+ if (StringUtils.isNotEmpty(version)) {
+ return version;
+ }
+ return consumerURL.getVersion();
+ }
+
+ /**
+ * FIXME, Avoid calling this method on the main line.
+ */
+// @Override
+// public Map<String, String> getParameters() {
+// Map<String, String> allParameters = new HashMap<>((int)(super.getParameters().size()/.75 + 1));
+// allParameters.putAll(super.getParameters());
+// if (consumerURL != null) {
+// allParameters.putAll(consumerURL.getParameters());
+// }
+// if (overriddenURL != null) {
+// allParameters.putAll(overriddenURL.getParameters());
+// }
+// allParameters.remove(CATEGORY_KEY);
+// return Collections.unmodifiableMap(allParameters);
+// }
+
+ @Override
+ public String getParameter(String key) {
+ String value = null;
+ if (consumerURL != null) {
+ value = consumerURL.getParameter(key);
+ }
+ if (StringUtils.isEmpty(value)) {
+ value = super.getParameter(key);
+ }
+ return value;
+ }
+
+ @Override
+ public String getMethodParameter(String method, String key) {
+ String value = null;
+ if (consumerURL != null) {
+ value = consumerURL.getMethodParameterStrict(method, key);
+ }
+ if (StringUtils.isEmpty(value)) {
+ value = super.getMethodParameterStrict(method, key);
+ }
+ if (StringUtils.isEmpty(value)) {
+ value = getParameter(key);
+ }
+ return value;
+ }
+
+ @Override
+ public String getAnyMethodParameter(String key) {
+ String value = null;
+ if (consumerURL != null) {
+ value = consumerURL.getAnyMethodParameter(key);
+ }
+ if (StringUtils.isEmpty(value)) {
+ value = super.getAnyMethodParameter(key);
+ }
+ return value;
+ }
+
+ @Override
+ public String getConcatenatedParameter(String key) {
+ if (concatenatedPrams == null) {
+ concatenatedPrams = new HashMap<>(1);
+ }
+ String value = concatenatedPrams.get(key);
+ if (StringUtils.isNotEmpty(value)) {
+ return value;
+ }
+
+ // Combine filters and listeners on Provider and Consumer
+ String remoteValue = super.getParameter(key);
+ String localValue = consumerURL.getParameter(key);
+ if (remoteValue != null && remoteValue.length() > 0
+ && localValue != null && localValue.length() > 0) {
+ value = remoteValue + "," + localValue;
+ concatenatedPrams.put(key, value);
+ return value;
+ }
+ if (localValue != null && localValue.length() > 0) {
+ value = localValue;
+ } else if (remoteValue != null && remoteValue.length() > 0) {
+ value = remoteValue;
+ }
+ concatenatedPrams.put(key, value);
+ return value;
+ }
+
+ @Override
+ public String getCategory() {
+ return PROVIDERS_CATEGORY;
+ }
+
+ @Override
+ public String getSide() {
+ return CONSUMER_SIDE;
+ }
+
+ public URL getConsumerURL() {
+ return consumerURL;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() ;
+ }
+
+ /**
+ * ignore consumer url compare.
+ * It's only meaningful for comparing two address urls related to the same consumerURL.
+ *
+ * @param obj
+ * @return
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof ServiceAddressURL)) {
+ return false;
+ }
+ return super.equals(obj);
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/ServiceConfigURL.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/ServiceConfigURL.java
new file mode 100644
index 0000000..2bbb062
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/ServiceConfigURL.java
@@ -0,0 +1,134 @@
+/*
+ * 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.common.url.component;
+
+import org.apache.dubbo.common.URL;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ServiceConfigURL extends URL {
+ private final Map<String, Object> attributes;
+
+ private volatile transient String full;
+ private volatile transient String string;
+ private volatile transient String identity;
+ private volatile transient String parameter;
+
+ public ServiceConfigURL() {
+ this.attributes = null;
+ }
+
+ public ServiceConfigURL(URLAddress urlAddress, URLParam urlParam, Map<String, Object> attributes) {
+ super(urlAddress, urlParam);
+ this.attributes = (attributes != null ? attributes : new HashMap<>());
+ }
+
+ public ServiceConfigURL(String protocol,
+ String username,
+ String password,
+ String host,
+ int port,
+ String path,
+ Map<String, String> parameters) {
+ this(new PathURLAddress(protocol, username, password, path, host, port), new URLParam(parameters), null);
+ }
+
+ public ServiceConfigURL(String protocol,
+ String username,
+ String password,
+ String host,
+ int port,
+ String path,
+ Map<String, String> parameters,
+ Map<String, Object> attributes) {
+ this(new PathURLAddress(protocol, username, password, path, host, port), new URLParam(parameters), attributes);
+ }
+
+ protected <T extends URL> T newURL(URLAddress urlAddress, URLParam urlParam) {
+ return (T) new ServiceConfigURL(urlAddress, urlParam, attributes);
+ }
+
+ public Map<String, Object> getAttributes() {
+ return attributes;
+ }
+
+ public Object getAttribute(String key) {
+ return attributes.get(key);
+ }
+
+ @Override
+ public URL addAttributes(Map<String, Object> attributes) {
+ Map<String, Object> newAttributes = new HashMap<>();
+ newAttributes.putAll(this.attributes);
+ newAttributes.putAll(attributes);
+
+ return new ServiceConfigURL(getUrlAddress(), getUrlParam(), newAttributes);
+ }
+
+ public ServiceConfigURL putAttribute(String key, Object obj) {
+ Map<String, Object> newAttributes = new HashMap<>(attributes);
+ newAttributes.put(key, obj);
+
+ return new ServiceConfigURL(getUrlAddress(), getUrlParam(), newAttributes);
+ }
+
+ @Override
+ public URL removeAttribute(String key) {
+ Map<String, Object> newAttributes = new HashMap<>(attributes);
+ newAttributes.remove(key);
+
+ return new ServiceConfigURL(getUrlAddress(), getUrlParam(), newAttributes);
+ }
+
+ @Override
+ public boolean hasAttribute(String key) {
+ return getAttribute(key) != null;
+ }
+
+ @Override
+ public String toString() {
+ if (string != null) {
+ return string;
+ }
+ return string = super.toString();
+ }
+
+ @Override
+ public String toFullString() {
+ if (full != null) {
+ return full;
+ }
+ return full = super.toFullString();
+ }
+
+ @Override
+ public String toIdentityString() {
+ if (identity != null) {
+ return identity;
+ }
+ return identity = super.toIdentityString();
+ }
+
+ @Override
+ public String toParameterString() {
+ if (parameter != null) {
+ return parameter;
+ }
+ return parameter = super.toParameterString();
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLAddress.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLAddress.java
new file mode 100644
index 0000000..614862a
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLAddress.java
@@ -0,0 +1,260 @@
+/*
+ * 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.common.url.component;
+
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.Objects;
+
+public class URLAddress implements Serializable {
+ private static final long serialVersionUID = -1985165475234910535L;
+
+ protected String host;
+ protected int port;
+
+ // cache
+ protected transient String rawAddress;
+ protected transient long timestamp;
+
+ public URLAddress(String host, int port) {
+ this(host, port, null);
+ }
+
+ public URLAddress(String host, int port, String rawAddress) {
+ this.host = host;
+ port = Math.max(port, 0);
+ this.port = port;
+
+ this.rawAddress = rawAddress;
+ this.timestamp = System.currentTimeMillis();
+ }
+
+ public String getProtocol() {
+ return "";
+ }
+
+ public URLAddress setProtocol(String protocol) {
+ return this;
+ }
+
+ public String getUsername() {
+ return "";
+ }
+
+ public URLAddress setUsername(String username) {
+ return this;
+ }
+
+ public String getPassword() {
+ return "";
+ }
+
+ public URLAddress setPassword(String password) {
+ return this;
+ }
+
+ public String getPath() {
+ return "";
+ }
+
+ public URLAddress setPath(String path) {
+ return this;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public URLAddress setHost(String host) {
+ return new URLAddress(host, port, rawAddress);
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public URLAddress setPort(int port) {
+ return new URLAddress(host, port, rawAddress);
+ }
+
+ public String getAddress() {
+ if (rawAddress == null) {
+ rawAddress = getAddress(getHost(), getPort());
+ }
+ return rawAddress;
+ }
+
+ public URLAddress setAddress(String host, int port) {
+ return new URLAddress(host, port, rawAddress);
+ }
+
+ public String getIp() {
+ return NetUtils.getIpByHost(getHost());
+ }
+
+ public String getRawAddress() {
+ return rawAddress;
+ }
+
+ protected String getAddress(String host, int port) {
+ return port <= 0 ? host : host + ':' + port;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(host, port);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (!(obj instanceof URLAddress)) return false;
+ URLAddress that = (URLAddress) obj;
+ return Objects.equals(this.getProtocol(), that.getProtocol()) &&
+ Objects.equals(this.getUsername(), that.getUsername()) &&
+ Objects.equals(this.getPassword(), that.getPassword()) &&
+ Objects.equals(this.getPath(), that.getPath()) &&
+ Objects.equals(this.getHost(), that.getHost()) &&
+ Objects.equals(this.getPort(), that.getPort());
+ }
+
+ @Override
+ public String toString() {
+ if (rawAddress != null) {
+ return rawAddress;
+ }
+
+ StringBuilder buf = new StringBuilder();
+ if (StringUtils.isNotEmpty(host)) {
+ buf.append(host);
+ if (port > 0) {
+ buf.append(":");
+ buf.append(port);
+ }
+ }
+ return buf.toString();
+ }
+
+ public static URLAddress parse(String rawAddress, String defaultProtocol, boolean encoded) {
+ try {
+ if (encoded) {
+ rawAddress = URLDecoder.decode(rawAddress, "UTF-8");
+ }
+
+ boolean isPathAddress = !Character.isDigit(rawAddress.charAt(0));
+ if (isPathAddress) {
+ return createPathURLAddress(rawAddress, defaultProtocol);
+ }
+ return createURLAddress(rawAddress, defaultProtocol);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
+ private static URLAddress createURLAddress(String rawAddress, String defaultProtocol) {
+ String host = null;
+ int port = 0;
+
+ int i = rawAddress.lastIndexOf(':');
+ if (i >= 0 && i < rawAddress.length() - 1) {
+ if (rawAddress.lastIndexOf('%') > i) {
+ // ipv6 address with scope id
+ // e.g. fe80:0:0:0:894:aeec:f37d:23e1%en0
+ // see https://howdoesinternetwork.com/2013/ipv6-zone-id
+ // ignore
+ } else {
+ port = Integer.parseInt(rawAddress.substring(i + 1));
+ host = rawAddress.substring(0, i);
+ }
+ } else {
+ host = rawAddress;
+ }
+
+ return new URLAddress(host, port, rawAddress);
+ }
+
+ private static PathURLAddress createPathURLAddress(String rawAddress, String defaultProtocol) {
+ String protocol = defaultProtocol;
+ String copyOfRawAddress = rawAddress;
+ String path = null, username = null, password = null, host = null;
+ int port = 0;
+ int i = rawAddress.indexOf("://");
+ if (i >= 0) {
+ if (i == 0) {
+ throw new IllegalStateException("url missing protocol: \"" + rawAddress + "\"");
+ }
+ protocol = rawAddress.substring(0, i);
+ rawAddress = rawAddress.substring(i + 3);
+ } else {
+ // case: file:/path/to/file.txt
+ i = rawAddress.indexOf(":/");
+ if (i >= 0) {
+ if (i == 0) {
+ throw new IllegalStateException("url missing protocol: \"" + rawAddress + "\"");
+ }
+ protocol = rawAddress.substring(0, i);
+ rawAddress = rawAddress.substring(i + 1);
+ }
+ }
+
+ i = rawAddress.indexOf('/');
+ if (i >= 0) {
+ path = rawAddress.substring(i + 1);
+ rawAddress = rawAddress.substring(0, i);
+ }
+ i = rawAddress.lastIndexOf('@');
+ if (i >= 0) {
+ username = rawAddress.substring(0, i);
+ int j = username.indexOf(':');
+ if (j >= 0) {
+ password = username.substring(j + 1);
+ username = username.substring(0, j);
+ }
+ rawAddress = rawAddress.substring(i + 1);
+ }
+ i = rawAddress.lastIndexOf(':');
+ if (i >= 0 && i < rawAddress.length() - 1) {
+ if (rawAddress.lastIndexOf('%') > i) {
+ // ipv6 address with scope id
+ // e.g. fe80:0:0:0:894:aeec:f37d:23e1%en0
+ // see https://howdoesinternetwork.com/2013/ipv6-zone-id
+ // ignore
+ } else {
+ port = Integer.parseInt(rawAddress.substring(i + 1));
+ host = rawAddress.substring(0, i);
+ }
+ }
+
+ // check cache
+ protocol = URLItemCache.checkProtocol(protocol);
+ path = URLItemCache.checkPath(path);
+
+ return new PathURLAddress(protocol, username, password, path, host, port, copyOfRawAddress);
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLItemCache.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLItemCache.java
new file mode 100644
index 0000000..2384493
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLItemCache.java
@@ -0,0 +1,67 @@
+/*
+ * 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.common.url.component;
+
+import org.apache.dubbo.common.utils.LRUCache;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class URLItemCache {
+ // thread safe with limited size, by default 1000
+ private static final Map<String, String> PARAM_KEY_CACHE = new LRUCache<>(10000);
+ private static final Map<String, String> PARAM_VALUE_CACHE = new LRUCache<>(100000);
+ private static final Map<String, String> PATH_CACHE = new LRUCache<>(10000);
+ private static final Map<String, String> PROTOCOL_CACHE = new ConcurrentHashMap<>();
+
+ public static void putParams(Map<String, String> params, String key, String value) {
+ String cachedKey = PARAM_KEY_CACHE.get(key);
+ if (cachedKey == null) {
+ cachedKey = key;
+ PARAM_KEY_CACHE.put(key, key);
+ }
+ String cachedValue = PARAM_VALUE_CACHE.get(value);
+ if (cachedValue == null) {
+ cachedValue = value;
+ PARAM_VALUE_CACHE.put(value, value);
+ }
+
+ params.put(cachedKey, cachedValue);
+ }
+
+ public static String checkProtocol(String _protocol) {
+ if (_protocol == null) {
+ return _protocol;
+ }
+ String cachedProtocol = PROTOCOL_CACHE.putIfAbsent(_protocol, _protocol);
+ if (cachedProtocol != null) {
+ return cachedProtocol;
+ }
+ return _protocol;
+ }
+
+ public static String checkPath(String _path) {
+ if (_path == null) {
+ return _path;
+ }
+ String cachedPath = PATH_CACHE.putIfAbsent(_path, _path);
+ if (cachedPath != null) {
+ return cachedPath;
+ }
+ return _path;
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLParam.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLParam.java
new file mode 100644
index 0000000..b2dca0c
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLParam.java
@@ -0,0 +1,286 @@
+/*
+ * 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.common.url.component;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.URLStrParser;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.TreeMap;
+
+import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
+import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
+
+public class URLParam implements Serializable {
+ private static final long serialVersionUID = -1985165475234910535L;
+
+ private final String rawParam;
+ private final Map<String, String> params;
+
+ //cache
+ private transient Map<String, Map<String, String>> methodParameters;
+ private transient long timestamp;
+
+ public URLParam(Map<String, String> params) {
+ this(params, null);
+ }
+
+ public URLParam(Map<String, String> params, String rawParam) {
+ this.params = Collections.unmodifiableMap((params == null ? new HashMap<>() : new HashMap<>(params)));
+ this.rawParam = rawParam;
+
+ this.timestamp = System.currentTimeMillis();
+ }
+
+ public Map<String, Map<String, String>> getMethodParameters() {
+ if (methodParameters == null) {
+ methodParameters = Collections.unmodifiableMap(initMethodParameters(this.params));
+ }
+ return methodParameters;
+ }
+
+ public static Map<String, Map<String, String>> initMethodParameters(Map<String, String> parameters) {
+ Map<String, Map<String, String>> methodParameters = new HashMap<>();
+ if (parameters == null) {
+ return methodParameters;
+ }
+
+ String methodsString = parameters.get(METHODS_KEY);
+ if (StringUtils.isNotEmpty(methodsString)) {
+ String[] methods = methodsString.split(",");
+ for (Map.Entry<String, String> entry : parameters.entrySet()) {
+ String key = entry.getKey();
+ for (String method : methods) {
+ String methodPrefix = method + '.';
+ if (key.startsWith(methodPrefix)) {
+ String realKey = key.substring(methodPrefix.length());
+ URL.putMethodParameter(method, realKey, entry.getValue(), methodParameters);
+ }
+ }
+ }
+ } else {
+ for (Map.Entry<String, String> entry : parameters.entrySet()) {
+ String key = entry.getKey();
+ int methodSeparator = key.indexOf('.');
+ if (methodSeparator > 0) {
+ String method = key.substring(0, methodSeparator);
+ String realKey = key.substring(methodSeparator + 1);
+ URL.putMethodParameter(method, realKey, entry.getValue(), methodParameters);
+ }
+ }
+ }
+ return methodParameters;
+ }
+
+ public Map<String, String> getParameters() {
+ return params;
+ }
+
+ public URLParam addParameter(String key, String value) {
+ if (StringUtils.isEmpty(key)
+ || StringUtils.isEmpty(value)) {
+ return this;
+ }
+ // if value doesn't change, return immediately
+ if (value.equals(getParameters().get(key))) { // value != null
+ return this;
+ }
+
+ Map<String, String> map = new HashMap<>(getParameters());
+ map.put(key, value);
+ return new URLParam(map, rawParam);
+ }
+
+ public URLParam addParameterIfAbsent(String key, String value) {
+ if (StringUtils.isEmpty(key)
+ || StringUtils.isEmpty(value)) {
+ return this;
+ }
+ if (hasParameter(key)) {
+ return this;
+ }
+
+ Map<String, String> map = new HashMap<>(getParameters());
+ map.put(key, value);
+
+ return new URLParam(map, rawParam);
+ }
+
+ /**
+ * Add parameters to a new url.
+ *
+ * @param parameters parameters in key-value pairs
+ * @return A new URL
+ */
+ public URLParam addParameters(Map<String, String> parameters) {
+ if (CollectionUtils.isEmptyMap(parameters)) {
+ return this;
+ }
+
+ boolean hasAndEqual = true;
+ for (Map.Entry<String, String> entry : parameters.entrySet()) {
+ String value = getParameters().get(entry.getKey());
+ if (value == null) {
+ if (entry.getValue() != null) {
+ hasAndEqual = false;
+ break;
+ }
+ } else {
+ if (!value.equals(entry.getValue())) {
+ hasAndEqual = false;
+ break;
+ }
+ }
+ }
+ // return immediately if there's no change
+ if (hasAndEqual) {
+ return this;
+ }
+
+ Map<String, String> map = new HashMap<>((int)(getParameters().size() + parameters.size() / 0.75f) + 1);
+ map.putAll(getParameters());
+ map.putAll(parameters);
+ return new URLParam(map, rawParam);
+ }
+
+ public URLParam addParametersIfAbsent(Map<String, String> parameters) {
+ if (CollectionUtils.isEmptyMap(parameters)) {
+ return this;
+ }
+
+ Map<String, String> map = new HashMap<>((int)(getParameters().size() + parameters.size() / 0.75f) + 1);
+ map.putAll(parameters);
+ map.putAll(getParameters());
+ return new URLParam(map, rawParam);
+ }
+
+ public URLParam removeParameters(String... keys) {
+ if (keys == null || keys.length == 0) {
+ return this;
+ }
+
+ Map<String, String> map = new HashMap<>(getParameters());
+ for (String key : keys) {
+ map.remove(key);
+ }
+ if (map.size() == getParameters().size()) {
+ return this;
+ }
+ return new URLParam(map, rawParam);
+ }
+
+ public URLParam clearParameters() {
+ return new URLParam(new HashMap<>());
+ }
+
+ public boolean hasParameter(String key) {
+ String value = getParameter(key);
+ return value != null && value.length() > 0;
+ }
+
+ public String getParameter(String key) {
+ return params.get(key);
+ }
+
+ public String getRawParam() {
+ return rawParam;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(params);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (!(obj instanceof URLParam)) return false;
+ URLParam that = (URLParam) obj;
+ return Objects.equals(this.getParameters(), that.getParameters());
+ }
+
+ @Override
+ public String toString() {
+ if (StringUtils.isNotEmpty(rawParam)) {
+ return rawParam;
+ }
+ if (params == null) {
+ return "";
+ }
+
+ StringBuilder buf = new StringBuilder();
+ boolean first = true;
+ for (Map.Entry<String, String> entry : new TreeMap<>(params).entrySet()) {
+ if (StringUtils.isNotEmpty(entry.getKey())) {
+ if (first) {
+ first = false;
+ } else {
+ buf.append("&");
+ }
+ buf.append(entry.getKey());
+ buf.append("=");
+ buf.append(entry.getValue() == null ? "" : entry.getValue().trim());
+ }
+ }
+ return buf.toString();
+ }
+
+ public static URLParam parse(String rawParam, boolean encoded, Map<String, String> extraParameters) {
+ Map<String, String> parameters = URLStrParser.parseParams(rawParam, encoded);
+ if (CollectionUtils.isNotEmptyMap(extraParameters)) {
+ parameters.putAll(extraParameters);
+ }
+ return new URLParam(parameters, rawParam);
+ }
+
+ public static URLParam parse(String rawParam) {
+ String[] parts = rawParam.split("&");
+ Map<String, String> parameters = new HashMap<>((int) (parts.length/.75f) + 1);
+ for (String part : parts) {
+ part = part.trim();
+ if (part.length() > 0) {
+ int j = part.indexOf('=');
+ if (j >= 0) {
+ String key = part.substring(0, j);
+ String value = part.substring(j + 1);
+ parameters.put(key, value);
+ // compatible with lower versions registering "default." keys
+ if (key.startsWith(DEFAULT_KEY_PREFIX)) {
+ parameters.putIfAbsent(key.substring(DEFAULT_KEY_PREFIX.length()), value);
+ }
+ } else {
+ parameters.put(part, part);
+ }
+ }
+ }
+ return new URLParam(parameters, rawParam);
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java
index d45ada1..17ce7ad 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java
@@ -17,6 +17,7 @@
package org.apache.dubbo.common.utils;
import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.URLStrParser;
import org.apache.dubbo.common.constants.RemotingConstants;
import java.util.ArrayList;
@@ -31,6 +32,7 @@ import static java.util.Collections.emptyMap;
import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.CLASSIFIER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
+import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
@@ -102,7 +104,7 @@ public class UrlUtils {
defaultParameters.remove(PORT_KEY);
defaultParameters.remove(PATH_KEY);
}
- URL u = URL.valueOf(url);
+ URL u = URL.cacheableValueOf(url);
boolean changed = false;
String protocol = u.getProtocol();
String username = u.getUsername();
@@ -400,8 +402,8 @@ public class UrlUtils {
return false;
}
- if (!isMatchCategory(providerUrl.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY),
- consumerUrl.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY))) {
+ if (!isMatchCategory(providerUrl.getCategory(DEFAULT_CATEGORY),
+ consumerUrl.getCategory(DEFAULT_CATEGORY))) {
return false;
}
if (!providerUrl.getParameter(ENABLED_KEY, true)
@@ -409,12 +411,12 @@ public class UrlUtils {
return false;
}
- String consumerGroup = consumerUrl.getParameter(GROUP_KEY);
- String consumerVersion = consumerUrl.getParameter(VERSION_KEY);
+ String consumerGroup = consumerUrl.getGroup();
+ String consumerVersion = consumerUrl.getVersion();
String consumerClassifier = consumerUrl.getParameter(CLASSIFIER_KEY, ANY_VALUE);
- String providerGroup = providerUrl.getParameter(GROUP_KEY);
- String providerVersion = providerUrl.getParameter(VERSION_KEY);
+ String providerGroup = providerUrl.getGroup();
+ String providerVersion = providerUrl.getVersion();
String providerClassifier = providerUrl.getParameter(CLASSIFIER_KEY, ANY_VALUE);
return (ANY_VALUE.equals(consumerGroup) || StringUtils.isEquals(consumerGroup, providerGroup) || StringUtils.isContains(consumerGroup, providerGroup))
&& (ANY_VALUE.equals(consumerVersion) || StringUtils.isEquals(consumerVersion, providerVersion))
@@ -463,10 +465,10 @@ public class UrlUtils {
public static boolean isServiceKeyMatch(URL pattern, URL value) {
return pattern.getParameter(INTERFACE_KEY).equals(
value.getParameter(INTERFACE_KEY))
- && isItemMatch(pattern.getParameter(GROUP_KEY),
- value.getParameter(GROUP_KEY))
- && isItemMatch(pattern.getParameter(VERSION_KEY),
- value.getParameter(VERSION_KEY));
+ && isItemMatch(pattern.getGroup(),
+ value.getGroup())
+ && isItemMatch(pattern.getVersion(),
+ value.getVersion());
}
public static List<URL> classifyUrls(List<URL> urls, Predicate<URL> predicate) {
@@ -475,22 +477,24 @@ public class UrlUtils {
public static boolean isConfigurator(URL url) {
return OVERRIDE_PROTOCOL.equals(url.getProtocol()) ||
- CONFIGURATORS_CATEGORY.equals(url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY));
+ CONFIGURATORS_CATEGORY.equals(url.getCategory(DEFAULT_CATEGORY));
}
public static boolean isRoute(URL url) {
return ROUTE_PROTOCOL.equals(url.getProtocol()) ||
- ROUTERS_CATEGORY.equals(url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY));
+ ROUTERS_CATEGORY.equals(url.getCategory(DEFAULT_CATEGORY));
}
public static boolean isProvider(URL url) {
return !OVERRIDE_PROTOCOL.equals(url.getProtocol()) &&
!ROUTE_PROTOCOL.equals(url.getProtocol()) &&
- PROVIDERS_CATEGORY.equals(url.getParameter(CATEGORY_KEY, PROVIDERS_CATEGORY));
+ PROVIDERS_CATEGORY.equals(url.getCategory(PROVIDERS_CATEGORY));
}
public static boolean isRegistry(URL url) {
- return REGISTRY_PROTOCOL.equals(url.getProtocol()) || SERVICE_REGISTRY_PROTOCOL.equalsIgnoreCase(url.getProtocol());
+ return REGISTRY_PROTOCOL.equals(url.getProtocol())
+ || SERVICE_REGISTRY_PROTOCOL.equalsIgnoreCase(url.getProtocol())
+ || (url.getProtocol() != null && url.getProtocol().endsWith("-registry-protocol"));
}
/**
@@ -553,4 +557,101 @@ public class UrlUtils {
arr[1] = serviceKey;
return arr;
}
+
+ /**
+ * NOTICE: This method allocate too much objects, we can use {@link URLStrParser#parseDecodedStr(String)} instead.
+ * <p>
+ * Parse url string
+ *
+ * @param url URL string
+ * @return URL instance
+ * @see URL
+ */
+ public static URL valueOf(String url) {
+ if (url == null || (url = url.trim()).length() == 0) {
+ throw new IllegalArgumentException("url == null");
+ }
+ String protocol = null;
+ String username = null;
+ String password = null;
+ String host = null;
+ int port = 0;
+ String path = null;
+ Map<String, String> parameters = null;
+ int i = url.indexOf('?'); // separator between body and parameters
+ if (i >= 0) {
+ String[] parts = url.substring(i + 1).split("&");
+ parameters = new HashMap<>();
+ for (String part : parts) {
+ part = part.trim();
+ if (part.length() > 0) {
+ int j = part.indexOf('=');
+ if (j >= 0) {
+ String key = part.substring(0, j);
+ String value = part.substring(j + 1);
+ parameters.put(key, value);
+ // compatible with lower versions registering "default." keys
+ if (key.startsWith(DEFAULT_KEY_PREFIX)) {
+ parameters.putIfAbsent(key.substring(DEFAULT_KEY_PREFIX.length()), value);
+ }
+ } else {
+ parameters.put(part, part);
+ }
+ }
+ }
+ url = url.substring(0, i);
+ }
+ i = url.indexOf("://");
+ if (i >= 0) {
+ if (i == 0) {
+ throw new IllegalStateException("url missing protocol: \"" + url + "\"");
+ }
+ protocol = url.substring(0, i);
+ url = url.substring(i + 3);
+ } else {
+ // case: file:/path/to/file.txt
+ i = url.indexOf(":/");
+ if (i >= 0) {
+ if (i == 0) {
+ throw new IllegalStateException("url missing protocol: \"" + url + "\"");
+ }
+ protocol = url.substring(0, i);
+ url = url.substring(i + 1);
+ }
+ }
+
+ i = url.indexOf('/');
+ if (i >= 0) {
+ path = url.substring(i + 1);
+ url = url.substring(0, i);
+ }
+ i = url.lastIndexOf('@');
+ if (i >= 0) {
+ username = url.substring(0, i);
+ int j = username.indexOf(':');
+ if (j >= 0) {
+ password = username.substring(j + 1);
+ username = username.substring(0, j);
+ }
+ url = url.substring(i + 1);
+ }
+ i = url.lastIndexOf(':');
+ if (i >= 0 && i < url.length() - 1) {
+ if (url.lastIndexOf('%') > i) {
+ // ipv6 address with scope id
+ // e.g. fe80:0:0:0:894:aeec:f37d:23e1%en0
+ // see https://howdoesinternetwork.com/2013/ipv6-zone-id
+ // ignore
+ } else {
+ port = Integer.parseInt(url.substring(i + 1));
+ url = url.substring(0, i);
+ }
+ }
+ if (url.length() > 0) {
+ host = url;
+ }
+
+ return new URL(protocol, username, password, host, port, path, parameters);
+ }
+
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/ApplicationConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/ApplicationConfig.java
index 06bf05e..e8d79ee 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/ApplicationConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/ApplicationConfig.java
@@ -37,6 +37,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DUMP_DIRECTORY;
import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.METADATA_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_LOCAL_FILE_CACHE_ENABLED;
import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
import static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;
import static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;
@@ -160,6 +161,8 @@ public class ApplicationConfig extends AbstractConfig {
private String repository;
+ private Boolean enableFileCache;
+
private Boolean publishInterface;
public ApplicationConfig() {
@@ -448,6 +451,15 @@ public class ApplicationConfig extends AbstractConfig {
this.repository = repository;
}
+ @Parameter(key = REGISTRY_LOCAL_FILE_CACHE_ENABLED)
+ public Boolean getEnableFileCache() {
+ return enableFileCache;
+ }
+
+ public void setEnableFileCache(Boolean enableFileCache) {
+ this.enableFileCache = enableFileCache;
+ }
+
@Parameter(key = REGISTRY_PUBLISH_INTERFACE_KEY)
public Boolean getPublishInterface() {
return publishInterface;
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/support/ProtocolUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/support/ProtocolUtils.java
index 801132f..85920e2 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/support/ProtocolUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/support/ProtocolUtils.java
@@ -27,8 +27,6 @@ import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZ
import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_DEFAULT;
import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_NATIVE_JAVA;
import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_PROTOBUF;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
public class ProtocolUtils {
@@ -38,8 +36,8 @@ public class ProtocolUtils {
}
public static String serviceKey(URL url) {
- return serviceKey(url.getPort(), url.getPath(), url.getParameter(VERSION_KEY),
- url.getParameter(GROUP_KEY));
+ return serviceKey(url.getPort(), url.getPath(), url.getVersion(),
+ url.getGroup());
}
public static String serviceKey(int port, String serviceName, String serviceVersion, String serviceGroup) {
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/InterfaceAddressURLTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/InterfaceAddressURLTest.java
new file mode 100644
index 0000000..8aad037
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/InterfaceAddressURLTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.common;
+
+import org.apache.dubbo.common.url.component.DubboServiceAddressURL;
+import org.apache.dubbo.common.url.component.ServiceAddressURL;
+import org.apache.dubbo.common.url.component.ServiceConfigURL;
+
+import org.junit.jupiter.api.Test;
+
+import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+
+public class InterfaceAddressURLTest {
+ private static final String rawURL = "dubbo://10.20.130.230:20880/context/path?version=1.0.0&group=g1&application=provider&timeout=1000&category=provider&side=provider&sayHello.weight=222";
+ private static final URL overrideURL = URL.valueOf("override://10.20.130.230:20880/context/path?version=1.0.0&application=morgan&timeout=2000&category=configurators&sayHello.overrideKey=override");
+ private static final URL consumerURL = URL.valueOf("consumer://10.20.130.230/context/path?version=2.0.0,1.0.0&group=g2&application=morgan&timeout=3000&side=consumer&sayHello.timeout=5000");
+
+ @Test
+ public void testMergeOverriden() {
+ URL url = URL.valueOf(rawURL);
+ ServiceAddressURL interfaceAddressURL = new DubboServiceAddressURL(url.getUrlAddress(), url.getUrlParam(), null, null);
+ assertEquals("1000", interfaceAddressURL.getParameter(TIMEOUT_KEY));
+
+ ServiceAddressURL withConsumer = DubboServiceAddressURL.valueOf(rawURL, consumerURL);
+ assertEquals("3000", withConsumer.getParameter(TIMEOUT_KEY));
+
+ ServiceAddressURL withOverriden = DubboServiceAddressURL.valueOf(rawURL, consumerURL, (ServiceConfigURL) overrideURL);
+ assertEquals("2000", withOverriden.getParameter(TIMEOUT_KEY));
+ }
+
+ @Test
+ public void testGetParameter() {
+ URL url = URL.valueOf(rawURL);
+ ServiceAddressURL interfaceAddressURL = new DubboServiceAddressURL(url.getUrlAddress(), url.getUrlParam(), consumerURL, null);
+
+ assertEquals("3000", interfaceAddressURL.getParameter(TIMEOUT_KEY));
+ assertNotEquals("1.0.0", interfaceAddressURL.getVersion());
+
+ assertEquals("morgan", interfaceAddressURL.getApplication());
+ assertEquals("provider", interfaceAddressURL.getRemoteApplication());
+
+ assertEquals("dubbo", interfaceAddressURL.getProtocol());
+ assertEquals("context/path", interfaceAddressURL.getPath());
+
+ assertEquals("consumer", interfaceAddressURL.getSide());
+ assertEquals("1.0.0", interfaceAddressURL.getVersion());
+ assertEquals("g1", interfaceAddressURL.getGroup());
+ }
+
+ @Test
+ public void testGetMethodParameter() {
+ URL url = URL.valueOf(rawURL);
+ ServiceAddressURL interfaceAddressURL = new DubboServiceAddressURL(url.getUrlAddress(), url.getUrlParam(), consumerURL, (ServiceConfigURL) overrideURL);
+
+ assertEquals("5000", interfaceAddressURL.getMethodParameter("sayHello", TIMEOUT_KEY));
+ assertEquals("2000", interfaceAddressURL.getMethodParameter("non-exist-methods", TIMEOUT_KEY));
+ assertEquals("222", interfaceAddressURL.getMethodParameter("sayHello", "weight"));
+ assertEquals("222", interfaceAddressURL.getMethodParameter("sayHello", "weight"));
+ assertEquals("override", interfaceAddressURL.getMethodParameter("sayHello", "overrideKey"));
+ }
+
+ @Test
+ public void testURLEquals() {
+ URL url1 = URL.valueOf(rawURL);
+ URL url2 = URL.valueOf(rawURL);
+ assertNotSame(url1, url2);
+ assertEquals(url1, url2);
+
+ // with consumer
+ ServiceAddressURL withConsumer = new DubboServiceAddressURL(url1.getUrlAddress(), url1.getUrlParam(), consumerURL, null);
+ ServiceAddressURL withConsumer2 = new DubboServiceAddressURL(url1.getUrlAddress(), url1.getUrlParam(), consumerURL, null);
+ assertEquals(withConsumer, withConsumer2);
+
+ ServiceAddressURL withOverride = new DubboServiceAddressURL(url1.getUrlAddress(), url1.getUrlParam(), consumerURL, (ServiceConfigURL) overrideURL);
+ url2 = url2.addParameter("timeout", "4444");
+ ServiceAddressURL withOverride2 = new DubboServiceAddressURL(url2.getUrlAddress(), url2.getUrlParam(), consumerURL, (ServiceConfigURL) overrideURL);
+ assertNotEquals(url1, url2);
+ assertEquals(withOverride, withOverride2);
+ }
+
+ @Test
+ public void testToString() {
+ URL url1 = URL.valueOf(rawURL);
+ System.out.println(url1.toString());
+ ServiceAddressURL withConsumer = new DubboServiceAddressURL(url1.getUrlAddress(), url1.getUrlParam(), consumerURL, null);
+ System.out.println(withConsumer.toString());
+ ServiceAddressURL withOverride2 = new DubboServiceAddressURL(url1.getUrlAddress(), url1.getUrlParam(), consumerURL, (ServiceConfigURL) overrideURL);
+ System.out.println(withOverride2.toString());
+ }
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/URLBuilderTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/URLBuilderTest.java
index c607bd3..5fa5bec 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/URLBuilderTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/URLBuilderTest.java
@@ -40,7 +40,7 @@ public class URLBuilderTest {
.build();
assertThat(url2.getParameter("newKey1"), equalTo("newValue1"));
assertThat(url2.getParameter("newKey2"), equalTo("2"));
- assertThat(url2.getParameter("version"), equalTo("1"));
+ assertThat(url2.getVersion(), equalTo("1"));
}
@Test
@@ -84,7 +84,7 @@ public class URLBuilderTest {
.removeParameters(Arrays.asList("key2", "application"))
.build();
assertThat(url2.getParameters().size(), equalTo(1));
- assertThat(url2.getParameter("version"), equalTo("1.0.0"));
+ assertThat(url2.getVersion(), equalTo("1.0.0"));
}
@Test
@@ -94,7 +94,7 @@ public class URLBuilderTest {
.addParameterIfAbsent("absentKey", "absentValue")
.addParameterIfAbsent("version", "2.0.0") // should not override
.build();
- assertThat(url2.getParameter("version"), equalTo("1.0.0"));
+ assertThat(url2.getVersion(), equalTo("1.0.0"));
assertThat(url2.getParameter("absentKey"), equalTo("absentValue"));
}
}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/URLTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/URLTest.java
index 5ba606d..b48dbdb 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/URLTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/URLTest.java
@@ -50,7 +50,7 @@ public class URLTest {
assertEquals(0, url.getPort());
assertEquals("context/path", url.getPath());
assertEquals(2, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("morgan", url.getParameter("application"));
url = URL.valueOf("context/path?version=1.0.0&application=morgan");
@@ -63,7 +63,7 @@ public class URLTest {
assertEquals(0, url.getPort());
assertEquals("path", url.getPath());
assertEquals(2, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("morgan", url.getParameter("application"));
}
@@ -132,7 +132,7 @@ public class URLTest {
assertEquals(20880, url.getPort());
assertEquals("context/path", url.getPath());
assertEquals(2, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("morgan", url.getParameter("application"));
}
@@ -260,7 +260,7 @@ public class URLTest {
assertEquals(20880, url.getPort());
assertNull(url.getPath());
assertEquals(1, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan");
assertURLStrDecoder(url);
@@ -272,10 +272,10 @@ public class URLTest {
assertEquals(20880, url.getPort());
assertEquals("context/path", url.getPath());
assertEquals(2, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("morgan", url.getParameter("application"));
- url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&noValue");
+ url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&noValue=");
assertURLStrDecoder(url);
assertEquals("dubbo", url.getProtocol());
assertEquals("admin", url.getUsername());
@@ -285,7 +285,7 @@ public class URLTest {
assertEquals(20880, url.getPort());
assertEquals("context/path", url.getPath());
assertEquals(3, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("morgan", url.getParameter("application"));
assertEquals("noValue", url.getParameter("noValue"));
}
@@ -301,7 +301,7 @@ public class URLTest {
@Test
public void test_noValueKey() throws Exception {
- URL url = URL.valueOf("http://1.2.3.4:8080/path?k0&k1=v1");
+ URL url = URL.valueOf("http://1.2.3.4:8080/path?k0=&k1=v1");
assertURLStrDecoder(url);
assertTrue(url.hasParameter("k0"));
@@ -403,7 +403,7 @@ public class URLTest {
assertEquals(20880, url.getPort());
assertEquals("context/path", url.getPath());
assertEquals(2, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("morgan", url.getParameter("application"));
url = url.setPort(1);
@@ -417,7 +417,7 @@ public class URLTest {
assertEquals(1, url.getPort());
assertEquals("context/path", url.getPath());
assertEquals(2, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("morgan", url.getParameter("application"));
url = url.setPath("path");
@@ -431,7 +431,7 @@ public class URLTest {
assertEquals(1, url.getPort());
assertEquals("path", url.getPath());
assertEquals(2, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("morgan", url.getParameter("application"));
url = url.setProtocol("protocol");
@@ -445,7 +445,7 @@ public class URLTest {
assertEquals(1, url.getPort());
assertEquals("path", url.getPath());
assertEquals(2, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("morgan", url.getParameter("application"));
url = url.setUsername("username");
@@ -459,7 +459,7 @@ public class URLTest {
assertEquals(1, url.getPort());
assertEquals("path", url.getPath());
assertEquals(2, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("morgan", url.getParameter("application"));
url = url.setPassword("password");
@@ -473,7 +473,7 @@ public class URLTest {
assertEquals(1, url.getPort());
assertEquals("path", url.getPath());
assertEquals(2, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("morgan", url.getParameter("application"));
}
@@ -495,7 +495,7 @@ public class URLTest {
assertEquals("morgan", url.getParameter("application"));
assertEquals("v1", url.getParameter("k1"));
assertEquals("v2", url.getParameter("k2"));
- assertNull(url.getParameter("version"));
+ assertNull(url.getVersion());
url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&k1=v1&k2=v2");
url = url.removeParameters("version", "application", "NotExistedKey");
@@ -510,7 +510,7 @@ public class URLTest {
assertEquals(2, url.getParameters().size());
assertEquals("v1", url.getParameter("k1"));
assertEquals("v2", url.getParameter("k2"));
- assertNull(url.getParameter("version"));
+ assertNull(url.getVersion());
assertNull(url.getParameter("application"));
url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&k1=v1&k2=v2");
@@ -526,7 +526,7 @@ public class URLTest {
assertEquals(2, url.getParameters().size());
assertEquals("v1", url.getParameter("k1"));
assertEquals("v2", url.getParameter("k2"));
- assertNull(url.getParameter("version"));
+ assertNull(url.getVersion());
assertNull(url.getParameter("application"));
}
@@ -769,7 +769,7 @@ public class URLTest {
assertEquals(20880, url.getPort());
assertEquals("context/path", url.getPath());
assertEquals(2, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("morgan", url.getParameter("application"));
}
@@ -787,7 +787,7 @@ public class URLTest {
assertEquals(20880, url.getPort());
assertEquals("context/path", url.getPath());
assertEquals(2, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("morgan", url.getParameter("application"));
}
@@ -801,7 +801,7 @@ public class URLTest {
assertEquals(0, url.getPort());
assertEquals("context/path", url.getPath());
assertEquals(2, url.getParameters().size());
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("morgan", url.getParameter("application"));
}
@@ -897,4 +897,20 @@ public class URLTest {
assertEquals(Integer.valueOf(1), url.getParameter("i", Integer.class));
assertEquals(Boolean.FALSE, url.getParameter("b", Boolean.class));
}
+
+ @Test
+ public void testEquals() {
+ URL url1 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group&version=1.0.0");
+ URL url2 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group&version=1.0.0");
+ Assertions.assertEquals(url1, url2);
+
+ URL url3 = URL.valueOf("10.20.130.230:20881/context/path?interface=org.apache.dubbo.test.interfaceName&group=group&version=1.0.0");
+ Assertions.assertNotEquals(url1, url3);
+
+ URL url4 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&weight=10&group=group&version=1.0.0");
+ Assertions.assertNotEquals(url1, url4);
+
+ URL url5 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&weight=10&group=group&version=1.0.0");
+ Assertions.assertEquals(url4, url5);
+ }
}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReportTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReportTest.java
index ed737ef..ea54e9f 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReportTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReportTest.java
@@ -17,7 +17,7 @@
package org.apache.dubbo.common.threadpool.support;
import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport;
+
import org.junit.jupiter.api.Test;
import java.util.concurrent.Executors;
@@ -27,7 +27,7 @@ import java.util.concurrent.ThreadPoolExecutor;
public class AbortPolicyWithReportTest {
@Test
public void jStackDumpTest() throws InterruptedException {
- URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?dump.directory=/tmp&version=1.0.0&application=morgan&noValue");
+ URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?dump.directory=/tmp&version=1.0.0&application=morgan&noValue=");
AbortPolicyWithReport abortPolicyWithReport = new AbortPolicyWithReport("Test", url);
try {
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/UrlUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/UrlUtilsTest.java
index a29c8e9..dc0eda6 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/UrlUtilsTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/UrlUtilsTest.java
@@ -367,7 +367,7 @@ public class UrlUtilsTest {
@Test
public void testIsMatchUrlWithDefaultPrefix() {
URL url = URL.valueOf("dubbo://127.0.0.1:20880/com.xxx.XxxService?default.version=1.0.0&default.group=test");
- assertEquals("1.0.0", url.getParameter("version"));
+ assertEquals("1.0.0", url.getVersion());
assertEquals("1.0.0", url.getParameter("default.version"));
URL consumerUrl = URL.valueOf("consumer://127.0.0.1/com.xxx.XxxService?version=1.0.0&group=test");
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
index 7c6d463..874944a 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
@@ -337,7 +337,7 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
url = url.setPath(interfaceName);
}
if (UrlUtils.isRegistry(url)) {
- urls.add(url.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
+ urls.add(url.putAttribute(REFER_KEY, map));
} else {
urls.add(ClusterUtils.mergeUrl(url, map));
}
@@ -354,7 +354,7 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
if (monitorUrl != null) {
map.put(MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
}
- urls.add(u.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
+ urls.add(u.putAttribute(REFER_KEY, map));
}
}
if (urls.isEmpty()) {
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
index e63c4f3..e2e8b09 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
@@ -484,9 +484,9 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
}
if (logger.isInfoEnabled()) {
if (url.getParameter(REGISTER_KEY, true)) {
- logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
+ logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url.getServiceKey() + " to registry " + registryURL.getAddress());
} else {
- logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
+ logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url.getServiceKey());
}
}
@@ -496,7 +496,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
registryURL = registryURL.addParameter(PROXY_KEY, proxy);
}
- Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
+ Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.putAttribute(EXPORT_KEY, url));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java
index 62e172d..45cb9c6 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java
@@ -275,7 +275,7 @@ public class ConfigValidationUtils {
return URLBuilder.from(registryURL)
.setProtocol(DUBBO_PROTOCOL)
.addParameter(PROTOCOL_KEY, monitor.getProtocol())
- .addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map))
+ .putAttribute(REFER_KEY, StringUtils.toQueryString(map))
.build();
}
return null;
@@ -529,7 +529,12 @@ public class ConfigValidationUtils {
}
private static String extractRegistryType(URL url) {
- return isServiceDiscoveryRegistryType(url) ? SERVICE_REGISTRY_PROTOCOL : REGISTRY_PROTOCOL;
+ return isServiceDiscoveryRegistryType(url) ? SERVICE_REGISTRY_PROTOCOL : getRegistryProtocolType(url);
+ }
+
+ private static String getRegistryProtocolType(URL url) {
+ String registryProtocol = url.getParameter("registry-protocol-type");
+ return StringUtils.isNotEmpty(registryProtocol) ? registryProtocol : REGISTRY_PROTOCOL;
}
public static void checkExtension(Class<?> type, String property, String value) {
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ServiceConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ServiceConfigTest.java
index 4d157ff..ed46382 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ServiceConfigTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ServiceConfigTest.java
@@ -258,7 +258,7 @@ public class ServiceConfigTest {
@Test
public void testApplicationInUrl() {
service.export();
- Assertions.assertNotNull(service.toUrl().getParameter(APPLICATION_KEY));
- Assertions.assertEquals("app", service.toUrl().getParameter(APPLICATION_KEY));
+ Assertions.assertNotNull(service.toUrl().getApplication());
+ Assertions.assertEquals("app", service.toUrl().getApplication());
}
}
diff --git a/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java b/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java
index f191178..64626f7 100644
--- a/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java
+++ b/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java
@@ -44,11 +44,9 @@ import java.util.stream.Collectors;
import static org.apache.dubbo.common.config.configcenter.Constants.CONFIG_NAMESPACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
-import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
/**
* Apollo implementation, https://github.com/ctripcorp/apollo
@@ -97,7 +95,7 @@ public class ApolloDynamicConfiguration implements DynamicConfiguration {
}
String namespace = url.getParameter(CONFIG_NAMESPACE_KEY, DEFAULT_GROUP);
- String apolloNamespace = StringUtils.isEmpty(namespace) ? url.getParameter(GROUP_KEY, DEFAULT_GROUP) : namespace;
+ String apolloNamespace = StringUtils.isEmpty(namespace) ? url.getGroup(DEFAULT_GROUP) : namespace;
dubboConfig = ConfigService.getConfig(apolloNamespace);
dubboConfigFile = ConfigService.getConfigFile(apolloNamespace, ConfigFileFormat.Properties);
@@ -155,7 +153,7 @@ public class ApolloDynamicConfiguration implements DynamicConfiguration {
@Override
public String getConfig(String key, String group, long timeout) throws IllegalStateException {
if (StringUtils.isNotEmpty(group)) {
- if (group.equals(url.getParameter(APPLICATION_KEY))) {
+ if (group.equals(url.getApplication())) {
return ConfigService.getAppConfig().getProperty(key, null);
} else {
return ConfigService.getConfig(group).getProperty(key, null);
@@ -181,7 +179,7 @@ public class ApolloDynamicConfiguration implements DynamicConfiguration {
if (StringUtils.isEmpty(group)) {
return dubboConfigFile.getContent();
}
- if (group.equals(url.getParameter(APPLICATION_KEY))) {
+ if (group.equals(url.getApplication())) {
return ConfigService.getConfigFile(APOLLO_APPLICATION_KEY, ConfigFileFormat.Properties).getContent();
}
diff --git a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
index a96f843..fbdbf74 100644
--- a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
+++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
@@ -74,7 +74,7 @@ public class ZookeeperDynamicConfiguration extends TreePathDynamicConfiguration
*/
@Override
public String getInternalProperty(String key) {
- return zkClient.getContent(key);
+ return zkClient.getContent(buildPathKey("", key));
}
@Override
diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/pom.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/pom.xml
new file mode 100644
index 0000000..bceae6a
--- /dev/null
+++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/pom.xml
@@ -0,0 +1,107 @@
+<!--
+ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-demo-xml</artifactId>
+ <version>${revision}</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <artifactId>dubbo-demo-xml-provider-backend</artifactId>
+ <packaging>jar</packaging>
+ <name>${project.artifactId}</name>
+ <description>The demo provider module of dubbo project</description>
+ <properties>
+ <skip_maven_deploy>true</skip_maven_deploy>
+ <slf4j-log4j12.version>1.7.25</slf4j-log4j12.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-demo-interface</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-registry-multicast</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-registry-nacos</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.alibaba.nacos</groupId>
+ <artifactId>nacos-client</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-registry-zookeeper</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-configcenter-zookeeper</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-configcenter-nacos</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-metadata-report-nacos</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-metadata-report-zookeeper</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-rpc-dubbo</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-config-spring</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-remoting-netty4</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-serialization-hessian2</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-qos</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>${slf4j-log4j12.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/java/org/apache/dubbo/demo/provider/chain/ChainApplication.java
similarity index 60%
copy from dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
copy to dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/java/org/apache/dubbo/demo/provider/chain/ChainApplication.java
index d5b3dbc..f57e635 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
+++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/java/org/apache/dubbo/demo/provider/chain/ChainApplication.java
@@ -1,36 +1,27 @@
-/*
- * 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;
-
-import org.apache.dubbo.common.Node;
-import org.apache.dubbo.common.URL;
-
-/**
- * Registry. (SPI, Prototype, ThreadSafe)
- *
- * @see org.apache.dubbo.registry.RegistryFactory#getRegistry(URL)
- * @see org.apache.dubbo.registry.support.AbstractRegistry
- */
-public interface Registry extends Node, RegistryService {
- default void reExportRegister(URL url) {
- register(url);
- }
-
- default void reExportUnregister(URL url) {
- unregister(url);
- }
-}
\ No newline at end of file
+/*
+ * 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.demo.provider.chain;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class ChainApplication {
+ public static void main(String[] args) throws Exception {
+ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-provider-chain.xml");
+ context.start();
+ System.in.read();
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/java/org/apache/dubbo/demo/provider/chain/ChainServiceImpl.java
similarity index 56%
copy from dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
copy to dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/java/org/apache/dubbo/demo/provider/chain/ChainServiceImpl.java
index d5b3dbc..bd15576 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
+++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/java/org/apache/dubbo/demo/provider/chain/ChainServiceImpl.java
@@ -1,36 +1,33 @@
-/*
- * 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;
-
-import org.apache.dubbo.common.Node;
-import org.apache.dubbo.common.URL;
-
-/**
- * Registry. (SPI, Prototype, ThreadSafe)
- *
- * @see org.apache.dubbo.registry.RegistryFactory#getRegistry(URL)
- * @see org.apache.dubbo.registry.support.AbstractRegistry
- */
-public interface Registry extends Node, RegistryService {
- default void reExportRegister(URL url) {
- register(url);
- }
-
- default void reExportUnregister(URL url) {
- unregister(url);
- }
-}
\ No newline at end of file
+/*
+ * 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.demo.provider.chain;
+
+import org.apache.dubbo.demo.ChainService;
+import org.apache.dubbo.rpc.RpcContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ChainServiceImpl implements ChainService {
+ private static final Logger logger = LoggerFactory.getLogger(ChainServiceImpl.class);
+
+ @Override
+ public String chain(String input) {
+ logger.info("Received " + input + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
+ return "Received " + input + ", response from provider: " + RpcContext.getContext().getLocalAddress();
+ }
+}
diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/resources/dubbo.properties b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/resources/dubbo.properties
new file mode 100644
index 0000000..ad602ba
--- /dev/null
+++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/resources/dubbo.properties
@@ -0,0 +1 @@
+dubbo.application.qos.port=22222
diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/resources/log4j.properties b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/resources/log4j.properties
new file mode 100644
index 0000000..15a0900
--- /dev/null
+++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/resources/log4j.properties
@@ -0,0 +1,7 @@
+###set log levels###
+log4j.rootLogger=info, stdout
+###output to the console###
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n
\ No newline at end of file
diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/resources/spring/dubbo-provider-chain.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/resources/spring/dubbo-provider-chain.xml
new file mode 100644
index 0000000..d677188
--- /dev/null
+++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider-backend/src/main/resources/spring/dubbo-provider-chain.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
+ xmlns="http://www.springframework.org/schema/beans"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
+ http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
+
+ <dubbo:application metadata-type="remote" name="demo-provider-chain"/>
+ <dubbo:metadata-report address="zookeeper://127.0.0.1:2181"/>
+
+ <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
+
+ <dubbo:protocol name="dubbo" port="-1"/>
+
+ <bean id="chainService" class="org.apache.dubbo.demo.provider.chain.ChainServiceImpl"/>
+
+ <dubbo:service group="g2" interface="org.apache.dubbo.demo.ChainService" ref="chainService"/>
+
+</beans>
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java
index 12d6665..b38b032 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java
@@ -28,8 +28,6 @@ import java.util.Set;
import static java.lang.String.valueOf;
import static java.util.Arrays.asList;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.rpc.model.ApplicationModel.getName;
/**
@@ -46,8 +44,8 @@ public class DynamicConfigurationServiceNameMapping implements ServiceNameMappin
@Override
public void map(URL url) {
String serviceInterface = url.getServiceInterface();
- String group = url.getParameter(GROUP_KEY);
- String version = url.getParameter(VERSION_KEY);
+ String group = url.getGroup();
+ String version = url.getVersion();
String protocol = url.getProtocol();
if (IGNORED_SERVICE_INTERFACES.contains(serviceInterface)) {
@@ -74,8 +72,8 @@ public class DynamicConfigurationServiceNameMapping implements ServiceNameMappin
@Override
public Set<String> getAndListen(URL url, MappingListener mappingListener) {
String serviceInterface = url.getServiceInterface();
- String group = url.getParameter(GROUP_KEY);
- String version = url.getParameter(VERSION_KEY);
+ String group = url.getGroup();
+ String version = url.getVersion();
String protocol = url.getProtocol();
DynamicConfiguration dynamicConfiguration = DynamicConfiguration.getDynamicConfiguration();
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfo.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfo.java
index 1564f36..0ad553d 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfo.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfo.java
@@ -19,6 +19,7 @@ package org.apache.dubbo.metadata;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.compiler.support.ClassUtils;
import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.url.component.URLParam;
import org.apache.dubbo.common.utils.ArrayUtils;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.StringUtils;
@@ -38,9 +39,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import static org.apache.dubbo.common.constants.CommonConstants.DOT_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_CHAR_SEPARATOR;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
public class MetadataInfo implements Serializable {
public static String DEFAULT_REVISION = "0";
@@ -210,7 +209,7 @@ public class MetadataInfo implements Serializable {
}
public ServiceInfo(URL url) {
- this(url.getServiceInterface(), url.getParameter(GROUP_KEY), url.getParameter(VERSION_KEY), url.getProtocol(), url.getPath(), null);
+ this(url.getServiceInterface(), url.getGroup(), url.getVersion(), url.getProtocol(), url.getPath(), null);
this.url = url;
Map<String, String> params = new HashMap<>();
@@ -339,8 +338,8 @@ public class MetadataInfo implements Serializable {
public String getMethodParameter(String method, String key, String defaultValue) {
if (methodParams == null) {
- methodParams = URL.toMethodParameters(params);
- consumerMethodParams = URL.toMethodParameters(consumerParams);
+ methodParams = URLParam.initMethodParameters(params);
+ consumerMethodParams = URLParam.initMethodParameters(consumerParams);
}
String value = getMethodParameter(method, key, consumerMethodParams);
@@ -372,8 +371,8 @@ public class MetadataInfo implements Serializable {
public boolean hasMethodParameter(String method) {
if (methodParams == null) {
- methodParams = URL.toMethodParameters(params);
- consumerMethodParams = URL.toMethodParameters(consumerParams);
+ methodParams = URLParam.initMethodParameters(params);
+ consumerMethodParams = URLParam.initMethodParameters(consumerParams);
}
return consumerMethodParams.containsKey(method) || methodParams.containsKey(method);
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifier.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifier.java
index ce7542f..b035a4f 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifier.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifier.java
@@ -18,11 +18,6 @@ package org.apache.dubbo.metadata.report.identifier;
import org.apache.dubbo.common.URL;
-import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
-
/**
* The MetadataIdentifier is used to store method descriptor.
* <p>
@@ -48,10 +43,10 @@ public class MetadataIdentifier extends BaseServiceMetadataIdentifier implements
public MetadataIdentifier(URL url) {
this.serviceInterface = url.getServiceInterface();
- this.version = url.getParameter(VERSION_KEY);
- this.group = url.getParameter(GROUP_KEY);
- this.side = url.getParameter(SIDE_KEY);
- setApplication(url.getParameter(APPLICATION_KEY));
+ this.version = url.getVersion();
+ this.group = url.getGroup();
+ this.side = url.getSide();
+ setApplication(url.getApplication());
}
public String getUniqueKey(KeyTypeEnum keyType) {
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/ServiceMetadataIdentifier.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/ServiceMetadataIdentifier.java
index 01a2196..100d844 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/ServiceMetadataIdentifier.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/ServiceMetadataIdentifier.java
@@ -18,9 +18,6 @@ package org.apache.dubbo.metadata.report.identifier;
import org.apache.dubbo.common.URL;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.metadata.MetadataConstants.KEY_REVISON_PREFIX;
/**
@@ -49,9 +46,9 @@ public class ServiceMetadataIdentifier extends BaseServiceMetadataIdentifier imp
public ServiceMetadataIdentifier(URL url) {
this.serviceInterface = url.getServiceInterface();
- this.version = url.getParameter(VERSION_KEY);
- this.group = url.getParameter(GROUP_KEY);
- this.side = url.getParameter(SIDE_KEY);
+ this.version = url.getVersion();
+ this.group = url.getGroup();
+ this.side = url.getSide();
this.protocol = url.getProtocol();
}
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/SubscriberMetadataIdentifier.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/SubscriberMetadataIdentifier.java
index 7a012e1..e375593 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/SubscriberMetadataIdentifier.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/SubscriberMetadataIdentifier.java
@@ -18,7 +18,6 @@ package org.apache.dubbo.metadata.report.identifier;
import org.apache.dubbo.common.URL;
-import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;
/**
@@ -38,7 +37,7 @@ public class SubscriberMetadataIdentifier extends BaseApplicationMetadataIdentif
public SubscriberMetadataIdentifier(URL url) {
- this.application = url.getParameter(APPLICATION_KEY, "");
+ this.application = url.getApplication("");
this.revision = url.getParameter(REVISION_KEY, "");
}
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java
index 1d39401..ab282fe 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java
@@ -61,11 +61,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
-import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
import static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
-import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
+import static org.apache.dubbo.common.utils.StringUtils.replace;
import static org.apache.dubbo.metadata.report.support.Constants.CYCLE_REPORT_KEY;
import static org.apache.dubbo.metadata.report.support.Constants.DEFAULT_METADATA_REPORT_CYCLE_REPORT;
import static org.apache.dubbo.metadata.report.support.Constants.DEFAULT_METADATA_REPORT_RETRY_PERIOD;
@@ -103,7 +102,11 @@ public abstract class AbstractMetadataReport implements MetadataReport {
public AbstractMetadataReport(URL reportServerURL) {
setUrl(reportServerURL);
// Start file save timer
- String defaultFilename = System.getProperty("user.home") + "/.dubbo/dubbo-metadata-" + reportServerURL.getParameter(APPLICATION_KEY) + "-" + reportServerURL.getAddress().replaceAll(":", "-") + ".cache";
+ String defaultFilename = System.getProperty("user.home") +
+ "/.dubbo/dubbo-metadata-" +
+ reportServerURL.getApplication() + "-" +
+ replace(reportServerURL.getAddress(), ":", "-") +
+ ".cache";
String filename = reportServerURL.getParameter(FILE_KEY, defaultFilename);
File file = null;
if (ConfigUtils.isNotEmpty(filename)) {
@@ -336,7 +339,7 @@ public abstract class AbstractMetadataReport implements MetadataReport {
}
String getProtocol(URL url) {
- String protocol = url.getParameter(SIDE_KEY);
+ String protocol = url.getSide();
protocol = protocol == null ? url.getProtocol() : protocol;
return protocol;
}
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/AbstractAbstractWritableMetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/AbstractAbstractWritableMetadataService.java
index 35054c9..d084477 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/AbstractAbstractWritableMetadataService.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/AbstractAbstractWritableMetadataService.java
@@ -25,10 +25,8 @@ import org.apache.dubbo.metadata.definition.model.ServiceDefinition;
import com.google.gson.Gson;
-import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
-import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
import static org.apache.dubbo.common.utils.ClassUtils.forName;
import static org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder.buildFullDefinition;
@@ -56,7 +54,7 @@ public abstract class AbstractAbstractWritableMetadataService implements Writabl
// Remove the useless parameters
url = url.removeParameters(PID_KEY, TIMESTAMP_KEY, BIND_IP_KEY, BIND_PORT_KEY, TIMESTAMP_KEY);
- String side = url.getParameter(SIDE_KEY);
+ String side = url.getSide();
if (PROVIDER_SIDE.equalsIgnoreCase(side)) {
publishProviderServiceDefinition(url);
} else {
@@ -72,7 +70,7 @@ public abstract class AbstractAbstractWritableMetadataService implements Writabl
}
protected String getServiceDefinition(URL exportedURL) {
- String interfaceName = exportedURL.getParameter(INTERFACE_KEY);
+ String interfaceName = exportedURL.getServiceInterface();
String json = null;
try {
if (StringUtils.isNotEmpty(interfaceName) && !isGeneric(exportedURL.getParameter(GENERIC_KEY))) {
diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/test/JTestMetadataReport4Test.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/test/JTestMetadataReport4Test.java
index 34ebce3..c52aff9 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/test/JTestMetadataReport4Test.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/test/JTestMetadataReport4Test.java
@@ -30,8 +30,6 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
-
/**
* ZookeeperRegistry
*/
@@ -48,7 +46,7 @@ public class JTestMetadataReport4Test extends AbstractMetadataReport {
private static String getProtocol(URL url) {
- String protocol = url.getParameter(SIDE_KEY);
+ String protocol = url.getSide();
protocol = protocol == null ? url.getProtocol() : protocol;
return protocol;
}
diff --git a/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReport.java b/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReport.java
index d7abde3..20a7742 100644
--- a/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReport.java
+++ b/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReport.java
@@ -19,6 +19,7 @@ package org.apache.dubbo.metadata.store.zookeeper;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.metadata.MappingChangedEvent;
import org.apache.dubbo.metadata.MappingListener;
@@ -45,7 +46,6 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;
/**
@@ -68,7 +68,7 @@ public class ZookeeperMetadataReport extends AbstractMetadataReport {
if (url.isAnyHost()) {
throw new IllegalStateException("registry address == null");
}
- String group = url.getParameter(GROUP_KEY, DEFAULT_ROOT);
+ String group = url.getGroup(DEFAULT_ROOT);
if (!group.startsWith(PATH_SEPARATOR)) {
group = PATH_SEPARATOR + group;
}
@@ -161,24 +161,32 @@ public class ZookeeperMetadataReport extends AbstractMetadataReport {
@Override
public Set<String> getServiceAppMapping(String serviceKey, MappingListener listener, URL url) {
- Set<String> appNameSet = new HashSet<>();
+ Set<String> appNameSet = new HashSet<>();
String path = toRootDir() + serviceKey;
- appNameSet.addAll(zkClient.getChildren(path));
+ List<String> appNameList = zkClient.getChildren(path);
+ if (!CollectionUtils.isEmpty(appNameList)) {
+ appNameSet.addAll(appNameList);
+ }
if (null == listenerMap.get(path)) {
- ChildListener zkListener = new ChildListener() {
- @Override
- public void childChanged(String path, List<String> children) {
- MappingChangedEvent event = new MappingChangedEvent();
- event.setServiceKey(serviceKey);
- event.setApps(null != children ? new HashSet<>(children): null);
- listener.onEvent(event);
- }
- };
- zkClient.addChildListener(path, zkListener);
- listenerMap.put(path, zkListener);
+ zkClient.create(path, false);
+ addServiceMappingListener(path, serviceKey, listener);
}
return appNameSet;
}
+
+ private void addServiceMappingListener(String path, String serviceKey, MappingListener listener) {
+ ChildListener zkListener = new ChildListener() {
+ @Override
+ public void childChanged(String path, List<String> children) {
+ MappingChangedEvent event = new MappingChangedEvent();
+ event.setServiceKey(serviceKey);
+ event.setApps(null != children ? new HashSet<>(children) : null);
+ listener.onEvent(event);
+ }
+ };
+ zkClient.addChildListener(path, zkListener);
+ listenerMap.put(path, zkListener);
+ }
}
diff --git a/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/support/MonitorFilter.java b/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/support/MonitorFilter.java
index 7b107cb..1492e0b 100644
--- a/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/support/MonitorFilter.java
+++ b/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/support/MonitorFilter.java
@@ -36,14 +36,12 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
-import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
-import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.monitor.Constants.COUNT_PROTOCOL;
import static org.apache.dubbo.rpc.Constants.INPUT_KEY;
@@ -150,15 +148,15 @@ public class MonitorFilter implements Filter, Filter.Listener {
// ---- service statistics ----
long elapsed = System.currentTimeMillis() - start; // invocation cost
int concurrent = getConcurrent(invoker, invocation).get(); // current concurrent count
- String application = invoker.getUrl().getParameter(APPLICATION_KEY);
+ String application = invoker.getUrl().getApplication();
String service = invoker.getInterface().getName(); // service name
String method = RpcUtils.getMethodName(invocation); // method name
- String group = invoker.getUrl().getParameter(GROUP_KEY);
- String version = invoker.getUrl().getParameter(VERSION_KEY);
+ String group = invoker.getUrl().getGroup();
+ String version = invoker.getUrl().getVersion();
int localPort;
String remoteKey, remoteValue;
- if (CONSUMER_SIDE.equals(invoker.getUrl().getParameter(SIDE_KEY))) {
+ if (CONSUMER_SIDE.equals(invoker.getUrl().getSide())) {
// ---- for service consumer ----
localPort = 0;
remoteKey = MonitorService.PROVIDER;
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Constants.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Constants.java
index 638af54..1bf4168 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Constants.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Constants.java
@@ -59,11 +59,6 @@ public interface Constants {
String REGISTRY_FILESAVE_SYNC_KEY = "save.file";
/**
- * Whether to cache locally, default is true
- */
- String REGISTRY__LOCAL_FILE_CACHE_ENABLED = "file.cache";
-
- /**
* Reconnection period in milliseconds for register center
*/
String REGISTRY_RECONNECT_PERIOD_KEY = "reconnect.period";
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
index d5b3dbc..084deff 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
@@ -19,6 +19,8 @@ package org.apache.dubbo.registry;
import org.apache.dubbo.common.Node;
import org.apache.dubbo.common.URL;
+import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_DELAY_NOTIFICATION_KEY;
+
/**
* Registry. (SPI, Prototype, ThreadSafe)
*
@@ -26,6 +28,10 @@ import org.apache.dubbo.common.URL;
* @see org.apache.dubbo.registry.support.AbstractRegistry
*/
public interface Registry extends Node, RegistryService {
+ default int getDelay() {
+ return getUrl().getParameter(REGISTRY_DELAY_NOTIFICATION_KEY, -1);
+ }
+
default void reExportRegister(URL url) {
register(url);
}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryNotifier.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryNotifier.java
new file mode 100644
index 0000000..babf5ce
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryNotifier.java
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+public abstract class RegistryNotifier {
+
+ private volatile long lastExecuteTime;
+ private volatile long lastEventTime;
+
+ private Object rawAddresses;
+ private Registry registry;
+
+ private ScheduledExecutorService scheduler = ExtensionLoader.getExtensionLoader(ExecutorRepository.class)
+ .getDefaultExtension().getRegistryNotificationExecutor();
+
+ public Registry getRegistry() {
+ return registry;
+ }
+
+ public RegistryNotifier(Registry registry) {
+ this.registry = registry;
+ }
+
+ public synchronized void notify(Object rawAddresses) {
+ this.rawAddresses = rawAddresses;
+ long notifyTime = System.currentTimeMillis();
+ this.lastEventTime = notifyTime;
+
+ int delayTime = getRegistry().getDelay();
+ long delta = (System.currentTimeMillis() - lastExecuteTime) - delayTime;
+ if (delta >= 0) {
+ scheduler.submit(new NotificationTask(this, notifyTime));
+ } else {
+ scheduler.schedule(new NotificationTask(this, notifyTime), -delta, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ protected abstract void doNotify(Object rawAddresses);
+
+ public static class NotificationTask implements Runnable {
+ private final RegistryNotifier listener;
+ private final long time;
+
+ public NotificationTask(RegistryNotifier listener, long time) {
+ this.listener = listener;
+ this.time = time;
+ }
+
+ @Override
+ public void run() {
+ if (this.time == listener.lastEventTime) {
+ listener.doNotify(listener.rawAddresses);
+ listener.lastExecuteTime = System.currentTimeMillis();
+ synchronized (listener) {
+ if (this.time == listener.lastEventTime) {
+ listener.rawAddresses = null;
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/InstanceAddressURL.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/InstanceAddressURL.java
index 51c9ffa..d2ee657 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/InstanceAddressURL.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/InstanceAddressURL.java
@@ -47,8 +47,6 @@ public class InstanceAddressURL extends URL {
) {
this.instance = instance;
this.metadataInfo = metadataInfo;
- this.host = instance.getHost();
- this.port = instance.getPort();
}
public ServiceInstance getInstance() {
@@ -93,6 +91,16 @@ public class InstanceAddressURL extends URL {
}
@Override
+ public String getHost() {
+ return instance.getHost();
+ }
+
+ @Override
+ public int getPort() {
+ return instance.getPort();
+ }
+
+ @Override
public String getPath() {
MetadataInfo.ServiceInfo serviceInfo = metadataInfo.getServiceInfo(getProtocolServiceKey());
if (serviceInfo == null) {
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java
index 65f50af..a6c7dd9 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java
@@ -60,7 +60,6 @@ import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.MAPPING_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.SIDE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDED_BY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_CLUSTER_KEY;
@@ -180,7 +179,7 @@ public class ServiceDiscoveryRegistry implements Registry {
protected boolean shouldRegister(URL providerURL) {
- String side = providerURL.getParameter(SIDE_KEY);
+ String side = providerURL.getSide();
boolean should = PROVIDER_SIDE.equals(side); // Only register the Provider.
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java
index aff9c22..540deaf 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java
@@ -21,6 +21,7 @@ import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
+import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.event.ConditionalEventListener;
import org.apache.dubbo.event.EventListener;
import org.apache.dubbo.metadata.MetadataInfo;
@@ -169,8 +170,12 @@ public class ServiceInstancesChangedListener implements ConditionalEventListener
this.notifyAddressChanged();
}
- public void addListener(String serviceKey, NotifyListener listener) {
+ public synchronized void addListener(String serviceKey, NotifyListener listener) {
this.listeners.put(serviceKey, listener);
+ List<URL> urls = this.serviceUrls.get(serviceKey);
+ if (CollectionUtils.isNotEmpty(urls)) {
+ listener.notify(urls);
+ }
}
public void removeListener(String serviceKey) {
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceNameMapping.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceNameMapping.java
index b6d7a9c..5c83825 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceNameMapping.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceNameMapping.java
@@ -31,8 +31,6 @@ import java.util.Set;
import static java.util.Arrays.asList;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.rpc.model.ApplicationModel.getName;
public class MetadataServiceNameMapping implements ServiceNameMapping {
@@ -41,8 +39,8 @@ public class MetadataServiceNameMapping implements ServiceNameMapping {
@Override
public void map(URL url) {
String serviceInterface = url.getServiceInterface();
- String group = url.getParameter(GROUP_KEY);
- String version = url.getParameter(VERSION_KEY);
+ String group = url.getGroup();
+ String version = url.getVersion();
String protocol = url.getProtocol();
if (IGNORED_SERVICE_INTERFACES.contains(serviceInterface)) {
@@ -56,8 +54,8 @@ public class MetadataServiceNameMapping implements ServiceNameMapping {
@Override
public Set<String> getAndListen(URL url, MappingListener mappingListener) {
String serviceInterface = url.getServiceInterface();
- String group = url.getParameter(GROUP_KEY);
- String version = url.getParameter(VERSION_KEY);
+ String group = url.getGroup();
+ String version = url.getVersion();
String protocol = url.getProtocol();
String mappingKey = ServiceNameMapping.buildGroup(serviceInterface, group, version, protocol);
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/InMemoryWritableMetadataService.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/InMemoryWritableMetadataService.java
index 44c6bbc..c2f03ee 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/InMemoryWritableMetadataService.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/InMemoryWritableMetadataService.java
@@ -48,7 +48,6 @@ import java.util.concurrent.locks.ReentrantLock;
import static java.util.Collections.emptySortedSet;
import static java.util.Collections.unmodifiableSortedSet;
import static org.apache.dubbo.common.URL.buildKey;
-import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty;
import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
@@ -165,7 +164,7 @@ public class InMemoryWritableMetadataService implements WritableMetadataService
@Override
public void publishServiceDefinition(URL providerUrl) {
try {
- String interfaceName = providerUrl.getParameter(INTERFACE_KEY);
+ String interfaceName = providerUrl.getServiceInterface();
if (StringUtils.isNotEmpty(interfaceName)
&& !ProtocolUtils.isGeneric(providerUrl.getParameter(GENERIC_KEY))) {
Class interfaceClass = Class.forName(interfaceName);
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/RemoteMetadataServiceImpl.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/RemoteMetadataServiceImpl.java
index 209a9fa..25bc03c 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/RemoteMetadataServiceImpl.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/RemoteMetadataServiceImpl.java
@@ -35,15 +35,10 @@ import org.apache.dubbo.rpc.RpcException;
import java.util.Map;
-import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
-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.PID_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
-import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_CLUSTER_KEY;
public class RemoteMetadataServiceImpl {
@@ -93,7 +88,7 @@ public class RemoteMetadataServiceImpl {
}
public void publishServiceDefinition(URL url) {
- String side = url.getParameter(SIDE_KEY);
+ String side = url.getSide();
if (PROVIDER_SIDE.equalsIgnoreCase(side)) {
//TODO, the params part is duplicate with that stored by exportURL(url), can be further optimized in the future.
publishProvider(url);
@@ -110,7 +105,7 @@ public class RemoteMetadataServiceImpl {
Constants.BIND_PORT_KEY, TIMESTAMP_KEY);
try {
- String interfaceName = providerUrl.getParameter(INTERFACE_KEY);
+ String interfaceName = providerUrl.getServiceInterface();
if (StringUtils.isNotEmpty(interfaceName)) {
Class interfaceClass = Class.forName(interfaceName);
FullServiceDefinition fullServiceDefinition = ServiceDefinitionBuilder.buildFullDefinition(interfaceClass,
@@ -118,8 +113,8 @@ public class RemoteMetadataServiceImpl {
for (Map.Entry<String, MetadataReport> entry : getMetadataReports().entrySet()) {
MetadataReport metadataReport = entry.getValue();
metadataReport.storeProviderMetadata(new MetadataIdentifier(providerUrl.getServiceInterface(),
- providerUrl.getParameter(VERSION_KEY), providerUrl.getParameter(GROUP_KEY),
- PROVIDER_SIDE, providerUrl.getParameter(APPLICATION_KEY)), fullServiceDefinition);
+ providerUrl.getVersion(), providerUrl.getGroup(),
+ PROVIDER_SIDE, providerUrl.getApplication()), fullServiceDefinition);
}
return;
}
@@ -135,8 +130,8 @@ public class RemoteMetadataServiceImpl {
Constants.BIND_PORT_KEY, TIMESTAMP_KEY);
getMetadataReports().forEach((registryKey, config) -> {
config.storeConsumerMetadata(new MetadataIdentifier(url.getServiceInterface(),
- url.getParameter(VERSION_KEY), url.getParameter(GROUP_KEY), CONSUMER_SIDE,
- url.getParameter(APPLICATION_KEY)), url.getParameters());
+ url.getVersion(), url.getGroup(), CONSUMER_SIDE,
+ url.getApplication()), url.getParameters());
});
}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/DefaultMigrationAddressComparator.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/DefaultMigrationAddressComparator.java
index 08ae6c9..aaa3b3b 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/DefaultMigrationAddressComparator.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/DefaultMigrationAddressComparator.java
@@ -35,11 +35,11 @@ public class DefaultMigrationAddressComparator implements MigrationAddressCompar
@Override
public <T> boolean shouldMigrate(ClusterInvoker<T> serviceDiscoveryInvoker, ClusterInvoker<T> invoker, MigrationRule rule) {
- if (!serviceDiscoveryInvoker.isAvailable()) {
+ if (!serviceDiscoveryInvoker.hasProxyInvokers()) {
logger.info("No instance address available, will not migrate.");
return false;
}
- if (!invoker.isAvailable()) {
+ if (!invoker.hasProxyInvokers()) {
logger.info("No interface address available, will migrate.");
return true;
}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationInvoker.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationInvoker.java
index f8a78cb..28b49ce 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationInvoker.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationInvoker.java
@@ -167,6 +167,7 @@ public class MigrationInvoker<T> implements MigrationClusterInvoker<T> {
switch (step) {
case APPLICATION_FIRST:
+ // FIXME, check ClusterInvoker.hasProxyInvokers() or ClusterInvoker.isAvailable()
if (checkInvokerAvailable(serviceDiscoveryInvoker)) {
currentAvailableInvoker = serviceDiscoveryInvoker;
} else {
@@ -186,8 +187,9 @@ public class MigrationInvoker<T> implements MigrationClusterInvoker<T> {
@Override
public boolean isAvailable() {
- return (invoker != null && invoker.isAvailable())
- || (serviceDiscoveryInvoker != null && serviceDiscoveryInvoker.isAvailable());
+ return currentAvailableInvoker != null
+ ? currentAvailableInvoker.isAvailable()
+ : (invoker != null && invoker.isAvailable()) || (serviceDiscoveryInvoker != null && serviceDiscoveryInvoker.isAvailable());
}
@Override
@@ -202,7 +204,9 @@ public class MigrationInvoker<T> implements MigrationClusterInvoker<T> {
@Override
public URL getUrl() {
- if (invoker != null) {
+ if (currentAvailableInvoker != null) {
+ return currentAvailableInvoker.getUrl();
+ } else if (invoker != null) {
return invoker.getUrl();
} else if (serviceDiscoveryInvoker != null) {
return serviceDiscoveryInvoker.getUrl();
@@ -213,17 +217,21 @@ public class MigrationInvoker<T> implements MigrationClusterInvoker<T> {
@Override
public URL getRegistryUrl() {
- if (invoker != null) {
+ if (currentAvailableInvoker != null) {
+ return currentAvailableInvoker.getRegistryUrl();
+ } else if (invoker != null) {
return invoker.getRegistryUrl();
} else if (serviceDiscoveryInvoker != null) {
- serviceDiscoveryInvoker.getRegistryUrl();
+ return serviceDiscoveryInvoker.getRegistryUrl();
}
return url;
}
@Override
public Directory<T> getDirectory() {
- if (invoker != null) {
+ if (currentAvailableInvoker != null) {
+ return currentAvailableInvoker.getDirectory();
+ } else if (invoker != null) {
return invoker.getDirectory();
} else if (serviceDiscoveryInvoker != null) {
return serviceDiscoveryInvoker.getDirectory();
@@ -233,8 +241,9 @@ public class MigrationInvoker<T> implements MigrationClusterInvoker<T> {
@Override
public boolean isDestroyed() {
- return (invoker == null || invoker.isDestroyed())
- && (serviceDiscoveryInvoker == null || serviceDiscoveryInvoker.isDestroyed());
+ return currentAvailableInvoker != null
+ ? currentAvailableInvoker.isDestroyed()
+ : (invoker == null || invoker.isDestroyed()) && (serviceDiscoveryInvoker == null || serviceDiscoveryInvoker.isDestroyed());
}
@Override
@@ -339,7 +348,7 @@ public class MigrationInvoker<T> implements MigrationClusterInvoker<T> {
}
protected synchronized void destroyInterfaceInvoker(ClusterInvoker<T> invoker) {
- if (checkInvokerAvailable(this.serviceDiscoveryInvoker)) {
+ if (this.serviceDiscoveryInvoker != null) {
this.currentAvailableInvoker = this.serviceDiscoveryInvoker;
updateConsumerModel(currentAvailableInvoker, invoker);
}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java
index 56dc3a9..61d33be 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java
@@ -17,7 +17,6 @@
package org.apache.dubbo.registry.integration;
import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.URLBuilder;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
@@ -41,14 +40,8 @@ import java.util.Collections;
import java.util.List;
import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
-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.MONITOR_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.CONSUMERS_CATEGORY;
-import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
import static org.apache.dubbo.registry.Constants.REGISTER_KEY;
import static org.apache.dubbo.registry.Constants.SIMPLIFIED_KEY;
import static org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol.DEFAULT_REGISTER_CONSUMER_KEYS;
@@ -108,8 +101,8 @@ public abstract class DynamicDirectory<T> extends AbstractDirectory<T> implement
this.serviceType = serviceType;
this.serviceKey = super.getConsumerUrl().getServiceKey();
- this.overrideDirectoryUrl = this.directoryUrl = turnRegistryUrlToConsumerUrl(url);
- String group = directoryUrl.getParameter(GROUP_KEY, "");
+ this.overrideDirectoryUrl = this.directoryUrl = consumerUrl;
+ String group = directoryUrl.getGroup("");
this.multiGroup = group != null && (ANY_VALUE.equals(group) || group.contains(","));
}
@@ -118,18 +111,6 @@ public abstract class DynamicDirectory<T> extends AbstractDirectory<T> implement
this.serviceListener = instanceListener;
}
- private URL turnRegistryUrlToConsumerUrl(URL url) {
- return URLBuilder.from(url)
- .setHost(queryMap.get(REGISTER_IP_KEY))
- .setPort(0)
- .setProtocol(queryMap.get(PROTOCOL_KEY) == null ? DUBBO : queryMap.get(PROTOCOL_KEY))
- .setPath(queryMap.get(INTERFACE_KEY))
- .clearParameters()
- .addParameters(queryMap)
- .removeParameter(MONITOR_KEY)
- .build();
- }
-
public void setProtocol(Protocol protocol) {
this.protocol = protocol;
}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java
index 03cd9bf..cf89e51 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java
@@ -17,11 +17,15 @@
package org.apache.dubbo.registry.integration;
import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.URLBuilder;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.url.component.DubboServiceAddressURL;
+import org.apache.dubbo.common.url.component.ServiceAddressURL;
+import org.apache.dubbo.common.url.component.ServiceConfigURL;
import org.apache.dubbo.common.utils.Assert;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.NetUtils;
@@ -39,7 +43,6 @@ import org.apache.dubbo.rpc.cluster.Router;
import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
import org.apache.dubbo.rpc.cluster.support.ClusterUtils;
import org.apache.dubbo.rpc.model.ApplicationModel;
-import org.apache.dubbo.rpc.protocol.InvokerWrapper;
import java.util.ArrayList;
import java.util.Collection;
@@ -53,12 +56,13 @@ import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DISABLED_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_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.PROTOCOL_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.APP_DYNAMIC_CONFIGURATORS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.COMPATIBLE_CONFIG_KEY;
@@ -73,6 +77,7 @@ import static org.apache.dubbo.common.constants.RegistryConstants.ROUTE_PROTOCOL
import static org.apache.dubbo.registry.Constants.CONFIGURATORS_SUFFIX;
import static org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol.DEFAULT_REGISTER_CONSUMER_KEYS;
import static org.apache.dubbo.remoting.Constants.CHECK_KEY;
+import static org.apache.dubbo.rpc.Constants.MOCK_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.ROUTER_KEY;
@@ -232,7 +237,7 @@ public class RegistryDirectory<T> extends DynamicDirectory<T> implements NotifyL
List<Invoker<T>> mergedInvokers = new ArrayList<>();
Map<String, List<Invoker<T>>> groupMap = new HashMap<>();
for (Invoker<T> invoker : invokers) {
- String group = invoker.getUrl().getParameter(GROUP_KEY, "");
+ String group = invoker.getUrl().getGroup("");
groupMap.computeIfAbsent(group, k -> new ArrayList<>());
groupMap.get(group).add(invoker);
}
@@ -294,7 +299,6 @@ public class RegistryDirectory<T> extends DynamicDirectory<T> implements NotifyL
if (urls == null || urls.isEmpty()) {
return newUrlInvokerMap;
}
- Set<URL> keys = new HashSet<>();
String queryProtocols = this.queryMap.get(PROTOCOL_KEY);
for (URL providerUrl : urls) {
// If protocol is configured at the reference side, only the matching protocol is selected
@@ -323,10 +327,6 @@ public class RegistryDirectory<T> extends DynamicDirectory<T> implements NotifyL
}
URL url = mergeUrl(providerUrl);
- if (keys.contains(url)) { // Repeated url
- continue;
- }
- keys.add(url);
// Cache key is url that does not merge with consumer side parameters, regardless of how the consumer combines parameters, if the server url changes, then refer again
Map<URL, Invoker<T>> localUrlInvokerMap = this.urlInvokerMap; // local reference
Invoker<T> invoker = localUrlInvokerMap == null ? null : localUrlInvokerMap.get(url);
@@ -339,7 +339,7 @@ public class RegistryDirectory<T> extends DynamicDirectory<T> implements NotifyL
enabled = url.getParameter(ENABLED_KEY, true);
}
if (enabled) {
- invoker = new InvokerDelegate<>(protocol.refer(serviceType, url), url, providerUrl);
+ invoker = protocol.refer(serviceType, url);
}
} catch (Throwable t) {
logger.error("Failed to refer invoker for interface:" + serviceType + ",url:(" + url + ")" + t.getMessage(), t);
@@ -351,7 +351,6 @@ public class RegistryDirectory<T> extends DynamicDirectory<T> implements NotifyL
newUrlInvokerMap.put(url, invoker);
}
}
- keys.clear();
return newUrlInvokerMap;
}
@@ -362,19 +361,24 @@ public class RegistryDirectory<T> extends DynamicDirectory<T> implements NotifyL
* @return
*/
private URL mergeUrl(URL providerUrl) {
- providerUrl = ClusterUtils.mergeProviderUrl(providerUrl, queryMap); // Merge the consumer side parameters
-
- providerUrl = overrideWithConfigurator(providerUrl);
-
- providerUrl = providerUrl.addParameter(Constants.CHECK_KEY, String.valueOf(false)); // Do not check whether the connection is successful or not, always create Invoker!
+ if (providerUrl instanceof ServiceAddressURL) {
+ providerUrl = overrideWithConfigurator(providerUrl);
+ } else {
+ providerUrl = ClusterUtils.mergeProviderUrl(providerUrl, queryMap); // Merge the consumer side parameters
+ providerUrl = overrideWithConfigurator(providerUrl);
+ providerUrl = providerUrl.addParameter(Constants.CHECK_KEY, String.valueOf(false)); // Do not check whether the connection is successful or not, always create Invoker!
+ }
- // The combination of directoryUrl and override is at the end of notify, which can't be handled here
-// this.overrideDirectoryUrl = this.overrideDirectoryUrl.addParametersIfAbsent(providerUrl.getParameters()); // Merge the provider side parameters
+ // FIXME, kept for mock
+ if (providerUrl.hasParameter(MOCK_KEY) || providerUrl.getAnyMethodParameter(MOCK_KEY) != null) {
+ providerUrl = providerUrl.removeParameter(TAG_KEY);
+ this.overrideDirectoryUrl = this.overrideDirectoryUrl.addParametersIfAbsent(providerUrl.getParameters());
+ }
if ((providerUrl.getPath() == null || providerUrl.getPath()
.length() == 0) && DUBBO_PROTOCOL.equals(providerUrl.getProtocol())) { // Compatible version 1.0
//fix by tony.chenl DUBBO-44
- String path = directoryUrl.getParameter(INTERFACE_KEY);
+ String path = directoryUrl.getServiceInterface();
if (path != null) {
int i = path.indexOf('/');
if (i >= 0) {
@@ -407,8 +411,29 @@ public class RegistryDirectory<T> extends DynamicDirectory<T> implements NotifyL
private URL overrideWithConfigurators(List<Configurator> configurators, URL url) {
if (CollectionUtils.isNotEmpty(configurators)) {
- for (Configurator configurator : configurators) {
- url = configurator.configure(url);
+ if (url instanceof DubboServiceAddressURL) {
+ DubboServiceAddressURL interfaceAddressURL = (DubboServiceAddressURL) url;
+ URL overriddenURL = interfaceAddressURL.getOverrideURL();
+ if (overriddenURL == null) {
+ String appName = interfaceAddressURL.getApplication();
+ String side = interfaceAddressURL.getSide();
+ overriddenURL = URLBuilder.from(interfaceAddressURL)
+ .clearParameters()
+ .addParameter(APPLICATION_KEY, appName)
+ .addParameter(SIDE_KEY, side).build();
+ }
+ for (Configurator configurator : configurators) {
+ overriddenURL = configurator.configure(overriddenURL);
+ }
+ url = new DubboServiceAddressURL(
+ interfaceAddressURL.getUrlAddress(),
+ interfaceAddressURL.getUrlParam(),
+ interfaceAddressURL.getConsumerURL(),
+ (ServiceConfigURL) overriddenURL);
+ } else {
+ for (Configurator configurator : configurators) {
+ url = configurator.configure(url);
+ }
}
}
return url;
@@ -561,7 +586,7 @@ public class RegistryDirectory<T> extends DynamicDirectory<T> implements NotifyL
}
private boolean isValidCategory(URL url) {
- String category = url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);
+ String category = url.getCategory(DEFAULT_CATEGORY);
if ((ROUTERS_CATEGORY.equals(category) || ROUTE_PROTOCOL.equals(url.getProtocol())) ||
PROVIDERS_CATEGORY.equals(category) ||
CONFIGURATORS_CATEGORY.equals(category) || DYNAMIC_CONFIGURATORS_CATEGORY.equals(category) ||
@@ -598,24 +623,6 @@ public class RegistryDirectory<T> extends DynamicDirectory<T> implements NotifyL
}
}
- /**
- * The delegate class, which is mainly used to store the URL address sent by the registry,and can be reassembled on the basis of providerURL queryMap overrideMap for re-refer.
- *
- * @param <T>
- */
- private static class InvokerDelegate<T> extends InvokerWrapper<T> {
- private URL providerUrl;
-
- public InvokerDelegate(Invoker<T> invoker, URL url, URL providerUrl) {
- super(invoker, url);
- this.providerUrl = providerUrl;
- }
-
- public URL getProviderUrl() {
- return providerUrl;
- }
- }
-
private static class ReferenceConfigurationListener extends AbstractConfiguratorListener {
private RegistryDirectory directory;
private URL url;
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
index eec9493..8b4a769 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
@@ -77,20 +77,18 @@ 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.RELEASE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.common.constants.FilterConstants.VALIDATION_KEY;
import static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;
import static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;
import static org.apache.dubbo.common.constants.QosConstants.QOS_HOST;
import static org.apache.dubbo.common.constants.QosConstants.QOS_PORT;
+import static org.apache.dubbo.common.constants.RegistryConstants.ALL_CATEGORIES;
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.OVERRIDE_PROTOCOL;
-import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;
-import static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_PROTOCOL;
import static org.apache.dubbo.common.utils.UrlUtils.classifyUrls;
import static org.apache.dubbo.registry.Constants.CONFIGURATORS_SUFFIX;
@@ -123,7 +121,7 @@ public class RegistryProtocol implements Protocol {
public static final String[] DEFAULT_REGISTER_PROVIDER_KEYS = {
APPLICATION_KEY, CODEC_KEY, EXCHANGER_KEY, SERIALIZATION_KEY, CLUSTER_KEY, CONNECTIONS_KEY, DEPRECATED_KEY,
GROUP_KEY, LOADBALANCE_KEY, MOCK_KEY, PATH_KEY, TIMEOUT_KEY, TOKEN_KEY, VERSION_KEY, WARMUP_KEY,
- WEIGHT_KEY, TIMESTAMP_KEY, DUBBO_VERSION_KEY, RELEASE_KEY
+ WEIGHT_KEY, DUBBO_VERSION_KEY, RELEASE_KEY
};
public static final String[] DEFAULT_REGISTER_CONSUMER_KEYS = {
@@ -177,8 +175,7 @@ public class RegistryProtocol implements Protocol {
return overrideListeners;
}
- private void register(URL registryUrl, URL registeredProviderUrl) {
- Registry registry = registryFactory.getRegistry(registryUrl);
+ private void register(Registry registry, URL registeredProviderUrl) {
registry.register(registeredProviderUrl);
}
@@ -209,13 +206,13 @@ public class RegistryProtocol implements Protocol {
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);
// url to registry
- final Registry registry = getRegistry(originInvoker);
+ final Registry registry = getRegistry(registryUrl);
final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
// decide if we need to delay publish
boolean register = providerUrl.getParameter(REGISTER_KEY, true);
if (register) {
- register(registryUrl, registeredProviderUrl);
+ register(registry, registeredProviderUrl);
}
// register stated url on provider model
@@ -316,7 +313,7 @@ public class RegistryProtocol implements Protocol {
if (getProviderUrl(originInvoker).getParameter(REGISTER_KEY, true)) {
Registry registry = null;
try {
- registry = getRegistry(originInvoker);
+ registry = getRegistry(getRegistryUrl(originInvoker));
} catch (Exception e) {
throw new SkipFailbackWrapperException(e);
}
@@ -350,11 +347,10 @@ public class RegistryProtocol implements Protocol {
/**
* Get an instance of registry based on the address of invoker
*
- * @param originInvoker
+ * @param registryUrl
* @return
*/
- protected Registry getRegistry(final Invoker<?> originInvoker) {
- URL registryUrl = getRegistryUrl(originInvoker);
+ protected Registry getRegistry(final URL registryUrl) {
return registryFactory.getRegistry(registryUrl);
}
@@ -411,11 +407,11 @@ public class RegistryProtocol implements Protocol {
* @return
*/
private URL getProviderUrl(final Invoker<?> originInvoker) {
- String export = originInvoker.getUrl().getParameterAndDecoded(EXPORT_KEY);
- if (export == null || export.length() == 0) {
- throw new IllegalArgumentException("The registry export url is null! registry: " + originInvoker.getUrl());
+ Object providerURL = originInvoker.getUrl().getAttribute(EXPORT_KEY);
+ if (!(providerURL instanceof URL)) {
+ throw new IllegalArgumentException("The registry export url is null! registry: " + originInvoker.getUrl().getAddress());
}
- return URL.valueOf(export);
+ return (URL)providerURL;
}
/**
@@ -440,7 +436,7 @@ public class RegistryProtocol implements Protocol {
}
// group="a,b" or group="*"
- Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY));
+ Map<String, String> qs = (Map<String, String>)url.getAttribute(REFER_KEY);
String group = qs.get(GROUP_KEY);
if (group != null && group.length() > 0) {
if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) {
@@ -512,7 +508,7 @@ public class RegistryProtocol implements Protocol {
}
public static URL toSubscribeUrl(URL url) {
- return url.addParameter(CATEGORY_KEY, PROVIDERS_CATEGORY + "," + CONFIGURATORS_CATEGORY + "," + ROUTERS_CATEGORY);
+ return url.addParameter(CATEGORY_KEY, ALL_CATEGORIES);
}
protected List<RegistryProtocolListener> findRegistryProtocolListeners(URL url) {
@@ -679,7 +675,7 @@ public class RegistryProtocol implements Protocol {
for (URL url : configuratorUrls) {
URL overrideUrl = url;
// Compatible with the old version
- if (url.getParameter(CATEGORY_KEY) == null && OVERRIDE_PROTOCOL.equals(url.getProtocol())) {
+ if (url.getCategory() == null && OVERRIDE_PROTOCOL.equals(url.getProtocol())) {
overrideUrl = url.addParameter(CATEGORY_KEY, CONFIGURATORS_CATEGORY);
}
@@ -773,7 +769,7 @@ public class RegistryProtocol implements Protocol {
String key = getCacheKey(this.originInvoker);
bounds.remove(key);
- Registry registry = RegistryProtocol.this.getRegistry(originInvoker);
+ Registry registry = RegistryProtocol.this.getRegistry(getRegistryUrl(originInvoker));
try {
registry.unregister(registerUrl);
} catch (Throwable t) {
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java
index efcd7e9..a73b75f 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java
@@ -54,16 +54,14 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
-import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
import static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_LOCAL_FILE_CACHE_ENABLED;
import static org.apache.dubbo.common.constants.RegistryConstants.ACCEPTS_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
import static org.apache.dubbo.registry.Constants.REGISTRY_FILESAVE_SYNC_KEY;
-import static org.apache.dubbo.registry.Constants.REGISTRY__LOCAL_FILE_CACHE_ENABLED;
/**
* AbstractRegistry. (SPI, Prototype, ThreadSafe)
@@ -92,13 +90,15 @@ public abstract class AbstractRegistry implements Registry {
private URL registryUrl;
// Local disk cache file
private File file;
+ private boolean localCacheEnabled;
public AbstractRegistry(URL url) {
setUrl(url);
- if (url.getParameter(REGISTRY__LOCAL_FILE_CACHE_ENABLED, true)) {
+ localCacheEnabled = url.getParameter(REGISTRY_LOCAL_FILE_CACHE_ENABLED, true);
+ if (localCacheEnabled) {
// Start file save timer
syncSaveFile = url.getParameter(REGISTRY_FILESAVE_SYNC_KEY, false);
- String defaultFilename = System.getProperty("user.home") + "/.dubbo/dubbo-registry-" + url.getParameter(APPLICATION_KEY) + "-" + url.getAddress().replaceAll(":", "-") + ".cache";
+ String defaultFilename = System.getProperty("user.home") + "/.dubbo/dubbo-registry-" + url.getApplication() + "-" + url.getAddress().replaceAll(":", "-") + ".cache";
String filename = url.getParameter(FILE_KEY, defaultFilename);
File file = null;
if (ConfigUtils.isNotEmpty(filename)) {
@@ -404,13 +404,13 @@ public abstract class AbstractRegistry implements Registry {
return;
}
if (logger.isInfoEnabled()) {
- logger.info("Notify urls for subscribe url " + url + ", urls: " + urls);
+ logger.info("Notify urls for subscribe url " + url + ", url size: " + urls.size());
}
// keep every provider's category.
Map<String, List<URL>> result = new HashMap<>();
for (URL u : urls) {
if (UrlUtils.isMatch(url, u)) {
- String category = u.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);
+ String category = u.getCategory(DEFAULT_CATEGORY);
List<URL> categoryList = result.computeIfAbsent(category, k -> new ArrayList<>());
categoryList.add(u);
}
@@ -426,7 +426,9 @@ public abstract class AbstractRegistry implements Registry {
listener.notify(categoryList);
// We will update our cache file after each notification.
// When our Registry has a subscribe failure due to network jitter, we can return at least the existing cache URL.
- saveProperties(url);
+ if (localCacheEnabled) {
+ saveProperties(url);
+ }
}
}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/CacheableFailbackRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/CacheableFailbackRegistry.java
new file mode 100644
index 0000000..9ca1b74
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/CacheableFailbackRegistry.java
@@ -0,0 +1,326 @@
+/*
+ * 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.support;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.URLBuilder;
+import org.apache.dubbo.common.URLStrParser;
+import org.apache.dubbo.common.config.ConfigurationUtils;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
+import org.apache.dubbo.common.url.component.DubboServiceAddressURL;
+import org.apache.dubbo.common.url.component.ServiceAddressURL;
+import org.apache.dubbo.common.url.component.URLAddress;
+import org.apache.dubbo.common.url.component.URLParam;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.common.utils.UrlUtils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.dubbo.common.URLStrParser.ENCODED_AND_MARK;
+import static org.apache.dubbo.common.URLStrParser.ENCODED_PID_KEY;
+import static org.apache.dubbo.common.URLStrParser.ENCODED_QUESTION_MARK;
+import static org.apache.dubbo.common.URLStrParser.ENCODED_TIMESTAMP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.CACHE_CLEAR_TASK_INTERVAL;
+import static org.apache.dubbo.common.constants.CommonConstants.CACHE_CLEAR_WAITING_THRESHOLD;
+import static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;
+import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_SEPARATOR_ENCODED;
+import static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
+import static org.apache.dubbo.common.constants.RegistryConstants.OVERRIDE_PROTOCOL;
+import static org.apache.dubbo.common.constants.RegistryConstants.ROUTE_PROTOCOL;
+
+/**
+ * Useful for registries who's sdk returns raw string as provider instance, for example, zookeeper and etcd.
+ */
+public abstract class CacheableFailbackRegistry extends FailbackRegistry {
+ private static final Logger logger = LoggerFactory.getLogger(CacheableFailbackRegistry.class);
+ private static String[] VARIABLE_KEYS = new String[]{ENCODED_TIMESTAMP_KEY, ENCODED_PID_KEY};
+
+ protected final static Map<String, URLAddress> stringAddress = new ConcurrentHashMap<>();
+ protected final static Map<String, URLParam> stringParam = new ConcurrentHashMap<>();
+ private static final ScheduledExecutorService cacheRemovalScheduler;
+ private static final int cacheRemovalTaskIntervalInMillis;
+ private static final int cacheClearWaitingThresholdInMillis;
+ private final static Map<ServiceAddressURL, Long> waitForRemove = new ConcurrentHashMap<>();
+ private static final Semaphore semaphore = new Semaphore(1);
+
+ private final Map<String, String> extraParameters;
+ protected final Map<URL, Map<String, ServiceAddressURL>> stringUrls = new HashMap<>();
+
+ static {
+ ExecutorRepository executorRepository = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
+ cacheRemovalScheduler = executorRepository.nextScheduledExecutor();
+ cacheRemovalTaskIntervalInMillis = getIntConfig(CACHE_CLEAR_TASK_INTERVAL, 10 * 60 * 1000);
+ cacheClearWaitingThresholdInMillis = getIntConfig(CACHE_CLEAR_WAITING_THRESHOLD, 10 * 60 * 1000);
+ }
+
+ public CacheableFailbackRegistry(URL url) {
+ super(url);
+ extraParameters = new HashMap<>(8);
+ extraParameters.put(CHECK_KEY, String.valueOf(false));
+ }
+
+ protected static int getIntConfig(String key, int def) {
+ String str = ConfigurationUtils.getProperty(key);
+ int result = def;
+ if (StringUtils.isNotEmpty(str)) {
+ try {
+ result = Integer.parseInt(str);
+ } catch (NumberFormatException e) {
+ logger.warn("Invalid registry properties configuration key " + key + ", value " + str);
+ }
+ }
+ return result;
+ }
+
+ protected List<URL> toUrlsWithoutEmpty(URL consumer, Collection<String> providers) {
+ // keep old urls
+ Map<String, ServiceAddressURL> oldURLs = stringUrls.get(consumer);
+ // create new urls
+ Map<String, ServiceAddressURL> newURLs;
+ URL copyOfConsumer = removeParamsFromConsumer(consumer);
+ if (oldURLs == null) {
+ newURLs = new HashMap<>();
+ for (String rawProvider : providers) {
+ rawProvider = stripOffVariableKeys(rawProvider);
+ ServiceAddressURL cachedURL = createURL(rawProvider, copyOfConsumer, getExtraParameters());
+ if (cachedURL == null) {
+ logger.warn("Invalid address, failed to parse into URL " + rawProvider);
+ continue;
+ }
+ newURLs.put(rawProvider, cachedURL);
+ }
+ } else {
+ newURLs = new HashMap<>((int)(oldURLs.size()/.75 + 1));
+ // maybe only default , or "env" + default
+ for (String rawProvider : providers) {
+ rawProvider = stripOffVariableKeys(rawProvider);
+ ServiceAddressURL cachedURL = oldURLs.remove(rawProvider);
+ if (cachedURL == null) {
+ cachedURL = createURL(rawProvider, copyOfConsumer, getExtraParameters());
+ if (cachedURL == null) {
+ logger.warn("Invalid address, failed to parse into URL " + rawProvider);
+ continue;
+ }
+ }
+ newURLs.put(rawProvider, cachedURL);
+ }
+ }
+
+ stringUrls.put(consumer, newURLs);
+
+ // destroy used urls
+ try {
+ if (oldURLs != null && oldURLs.size() > 0) {
+ Long currentTimestamp = System.currentTimeMillis();
+ for (Map.Entry<String, ServiceAddressURL> entry : oldURLs.entrySet()) {
+ waitForRemove.put(entry.getValue(), currentTimestamp);
+ }
+ if (CollectionUtils.isNotEmptyMap(waitForRemove)) {
+ if (semaphore.tryAcquire()) {
+ cacheRemovalScheduler.schedule(new RemovalTask(), cacheRemovalTaskIntervalInMillis, TimeUnit.MILLISECONDS);
+ }
+ }
+ }
+ } catch (Exception e) {
+ logger.warn("Failed to evict url for " + consumer, e);
+ }
+
+ return new ArrayList<>(newURLs.values());
+ }
+
+ protected List<URL> toUrlsWithEmpty(URL consumer, String path, Collection<String> providers) {
+ List<URL> urls;
+ if (CollectionUtils.isEmpty(providers)) {
+ urls = new ArrayList<>(1);
+ } else {
+ String rawProvider = providers.iterator().next();
+ if (rawProvider.startsWith(OVERRIDE_PROTOCOL) || rawProvider.startsWith(ROUTE_PROTOCOL)) {
+ urls = toConfiguratorsWithoutEmpty(consumer, providers);
+ } else {
+ urls = toUrlsWithoutEmpty(consumer, providers);
+ }
+ }
+ if (urls.isEmpty()) {
+ int i = path.lastIndexOf(PATH_SEPARATOR);
+ String category = i < 0 ? path : path.substring(i + 1);
+ URL empty = URLBuilder.from(consumer)
+ .setProtocol(EMPTY_PROTOCOL)
+ .addParameter(CATEGORY_KEY, category)
+ .build();
+ urls.add(empty);
+ }
+ return urls;
+ }
+
+ protected ServiceAddressURL createURL(String rawProvider, URL consumerURL, Map<String, String> extraParameters) {
+ boolean encoded = true;
+ // use encoded value directly to avoid URLDecoder.decode allocation.
+ int paramStartIdx = rawProvider.indexOf(ENCODED_QUESTION_MARK);
+ if (paramStartIdx == -1) {// if ENCODED_QUESTION_MARK does not shown, mark as not encoded.
+ encoded = false;
+ }
+ String[] parts = URLStrParser.parseRawURLToArrays(rawProvider, paramStartIdx);
+ if (parts.length <= 1) {
+ logger.warn("Received url without any parameters " + rawProvider);
+ return DubboServiceAddressURL.valueOf(rawProvider, consumerURL);
+ }
+
+ String rawAddress = parts[0];
+ String rawParams = parts[1];
+ boolean isEncoded = encoded;
+ URLAddress address = stringAddress.computeIfAbsent(rawAddress, k -> {
+ URLAddress newAddress = URLAddress.parse(k, getDefaultURLProtocol(), isEncoded);
+ stringAddress.put(k, newAddress);
+ return newAddress;
+ });
+ address.setTimestamp(System.currentTimeMillis());
+
+ URLParam param = stringParam.computeIfAbsent(rawParams, k -> {
+ URLParam newParam = URLParam.parse(k, isEncoded, extraParameters);
+ stringParam.put(k, newParam);
+ return newParam;
+ });
+ param.setTimestamp(System.currentTimeMillis());
+
+ ServiceAddressURL cachedURL = createServiceURL(address, param, consumerURL);
+ if (isMatch(consumerURL, cachedURL)) {
+ return cachedURL;
+ }
+ return null;
+ }
+
+
+ protected ServiceAddressURL createServiceURL(URLAddress address, URLParam param, URL consumerURL) {
+ return new DubboServiceAddressURL(address, param, consumerURL, null);
+ }
+
+ protected URL removeParamsFromConsumer(URL consumer) {
+ return consumer.removeParameters(RELEASE_KEY, DUBBO_VERSION_KEY, METHODS_KEY, TIMESTAMP_KEY, TAG_KEY);
+ }
+
+ private String stripOffVariableKeys(String rawProvider) {
+ String[] keys = getVariableKeys();
+ if (keys == null || keys.length == 0) {
+ return rawProvider;
+ }
+
+ for (String key : keys) {
+ int idxStart = rawProvider.indexOf(key);
+ if (idxStart == -1) {
+ continue;
+ }
+ int idxEnd = rawProvider.indexOf(ENCODED_AND_MARK, idxStart);
+ String part1 = rawProvider.substring(0, idxStart);
+ if (idxEnd == -1) {
+ rawProvider = part1;
+ } else {
+ String part2 = rawProvider.substring(idxEnd + ENCODED_AND_MARK.length());
+ rawProvider = part1 + part2;
+ }
+ }
+
+ if (rawProvider.endsWith(ENCODED_AND_MARK)) {
+ rawProvider = rawProvider.substring(0, rawProvider.length() - ENCODED_AND_MARK.length());
+ }
+ if (rawProvider.endsWith(ENCODED_QUESTION_MARK)) {
+ rawProvider = rawProvider.substring(0, rawProvider.length() - ENCODED_QUESTION_MARK.length());
+ }
+
+ return rawProvider;
+ }
+
+ private List<URL> toConfiguratorsWithoutEmpty(URL consumer, Collection<String> configurators) {
+ List<URL> urls = new ArrayList<>();
+ if (CollectionUtils.isNotEmpty(configurators)) {
+ for (String provider : configurators) {
+ if (provider.contains(PROTOCOL_SEPARATOR_ENCODED)) {
+ URL url = URLStrParser.parseEncodedStr(provider);
+ if (UrlUtils.isMatch(consumer, url)) {
+ urls.add(url);
+ }
+ }
+ }
+ }
+ return urls;
+ }
+
+ protected Map<String, String> getExtraParameters() {
+ return extraParameters;
+ }
+
+ protected String[] getVariableKeys() {
+ return VARIABLE_KEYS;
+ }
+
+ protected String getDefaultURLProtocol() {
+ return DUBBO;
+ }
+
+ protected abstract boolean isMatch(URL subscribeUrl, URL providerUrl);
+
+
+ private static class RemovalTask implements Runnable {
+ @Override
+ public void run() {
+ semaphore.release();
+ logger.info("Clearing cached URLs, size " + waitForRemove.size());
+ Iterator<Map.Entry<ServiceAddressURL, Long>> it = waitForRemove.entrySet().iterator();
+ while(it.hasNext()) {
+ Map.Entry<ServiceAddressURL, Long> entry = it.next();
+ ServiceAddressURL removeURL = entry.getKey();
+ long removeTime = entry.getValue();
+ long current = System.currentTimeMillis();
+ if (current - removeTime >= cacheClearWaitingThresholdInMillis) {
+ URLAddress urlAddress = removeURL.getUrlAddress();
+ URLParam urlParam = removeURL.getUrlParam();
+ if (current - urlAddress.getTimestamp() >= cacheClearWaitingThresholdInMillis) {
+ stringAddress.remove(urlAddress.getRawAddress());
+ }
+ if (current - urlParam.getTimestamp() >= cacheClearWaitingThresholdInMillis) {
+ stringParam.remove(urlParam.getRawParam());
+ }
+ it.remove();
+ }
+ }
+
+ if (semaphore.tryAcquire() && CollectionUtils.isNotEmptyMap(waitForRemove)) {//move to next schedule
+ cacheRemovalScheduler.schedule(new RemovalTask(), cacheRemovalTaskIntervalInMillis, TimeUnit.MILLISECONDS);
+ }
+ }
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/CacheableFailbackRegistryTest.java
similarity index 63%
copy from dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
copy to dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/CacheableFailbackRegistryTest.java
index d5b3dbc..6045e2c 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
+++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/CacheableFailbackRegistryTest.java
@@ -1,36 +1,37 @@
-/*
- * 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;
-
-import org.apache.dubbo.common.Node;
-import org.apache.dubbo.common.URL;
-
-/**
- * Registry. (SPI, Prototype, ThreadSafe)
- *
- * @see org.apache.dubbo.registry.RegistryFactory#getRegistry(URL)
- * @see org.apache.dubbo.registry.support.AbstractRegistry
- */
-public interface Registry extends Node, RegistryService {
- default void reExportRegister(URL url) {
- register(url);
- }
-
- default void reExportUnregister(URL url) {
- unregister(url);
- }
-}
\ No newline at end of file
+/*
+ * 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;
+
+public class CacheableFailbackRegistryTest {
+
+ public void testFullURLCache() {
+
+ }
+
+ public void testURLAddressCache() {
+
+ }
+
+ public void testURLParamCache() {
+
+ }
+
+ public void testRemove() {
+
+ }
+
+}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/DelayedRegistryNotifierTest.java
similarity index 62%
copy from dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
copy to dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/DelayedRegistryNotifierTest.java
index d5b3dbc..c158fdc 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
+++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/DelayedRegistryNotifierTest.java
@@ -1,36 +1,21 @@
-/*
- * 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;
-
-import org.apache.dubbo.common.Node;
-import org.apache.dubbo.common.URL;
-
-/**
- * Registry. (SPI, Prototype, ThreadSafe)
- *
- * @see org.apache.dubbo.registry.RegistryFactory#getRegistry(URL)
- * @see org.apache.dubbo.registry.support.AbstractRegistry
- */
-public interface Registry extends Node, RegistryService {
- default void reExportRegister(URL url) {
- register(url);
- }
-
- default void reExportUnregister(URL url) {
- unregister(url);
- }
-}
\ No newline at end of file
+/*
+ * 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;
+
+public class DelayedRegistryNotifierTest {
+
+}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/MockCacheableRegistryImpl.java
similarity index 54%
copy from dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
copy to dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/MockCacheableRegistryImpl.java
index d5b3dbc..2ebab9a 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
+++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/MockCacheableRegistryImpl.java
@@ -1,36 +1,65 @@
-/*
- * 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;
-
-import org.apache.dubbo.common.Node;
-import org.apache.dubbo.common.URL;
-
-/**
- * Registry. (SPI, Prototype, ThreadSafe)
- *
- * @see org.apache.dubbo.registry.RegistryFactory#getRegistry(URL)
- * @see org.apache.dubbo.registry.support.AbstractRegistry
- */
-public interface Registry extends Node, RegistryService {
- default void reExportRegister(URL url) {
- register(url);
- }
-
- default void reExportUnregister(URL url) {
- unregister(url);
- }
-}
\ No newline at end of file
+/*
+ * 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;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.registry.support.CacheableFailbackRegistry;
+
+/**
+ *
+ */
+public class MockCacheableRegistryImpl extends CacheableFailbackRegistry {
+
+ public MockCacheableRegistryImpl(URL url) {
+ super(url);
+ }
+
+ @Override
+ public int getDelay() {
+ return 0;
+ }
+
+ @Override
+ protected boolean isMatch(URL subscribeUrl, URL providerUrl) {
+ return false;
+ }
+
+ @Override
+ public void doRegister(URL url) {
+
+ }
+
+ @Override
+ public void doUnregister(URL url) {
+
+ }
+
+ @Override
+ public void doSubscribe(URL url, NotifyListener listener) {
+
+ }
+
+ @Override
+ public void doUnsubscribe(URL url, NotifyListener listener) {
+
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return false;
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleServiceDiscovery.java b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleServiceDiscovery.java
new file mode 100644
index 0000000..084376b
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleServiceDiscovery.java
@@ -0,0 +1,177 @@
+/*
+ * 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.multiple;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.utils.DefaultPage;
+import org.apache.dubbo.common.utils.Page;
+import org.apache.dubbo.event.ConditionalEventListener;
+import org.apache.dubbo.registry.client.ServiceDiscovery;
+import org.apache.dubbo.registry.client.ServiceDiscoveryFactory;
+import org.apache.dubbo.registry.client.ServiceInstance;
+import org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;
+import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class MultipleServiceDiscovery implements ServiceDiscovery {
+ public static final String REGISTRY_PREFIX_KEY = "child.";
+ private final Map<String, ServiceDiscovery> serviceDiscoveries = new ConcurrentHashMap<>();
+ private URL registryURL;
+ private ServiceInstance serviceInstance;
+ private String applicationName;
+
+ @Override
+ public void initialize(URL registryURL) throws Exception {
+ this.registryURL = registryURL;
+ this.applicationName = registryURL.getParameter(CommonConstants.APPLICATION_KEY);
+
+ Map<String, String> parameters = registryURL.getParameters();
+ for (String key : parameters.keySet()) {
+ if (key.startsWith(REGISTRY_PREFIX_KEY)) {
+ URL url = URL.valueOf(registryURL.getParameter(key)).addParameter(CommonConstants.APPLICATION_KEY, applicationName)
+ .addParameter("registry-type", "service");
+ ServiceDiscovery serviceDiscovery = ServiceDiscoveryFactory.getExtension(url).getServiceDiscovery(url);
+ serviceDiscovery.initialize(url);
+ serviceDiscoveries.put(key, serviceDiscovery);
+ }
+ }
+ }
+
+ @Override
+ public URL getUrl() {
+ return registryURL;
+ }
+
+ @Override
+ public void destroy() throws Exception {
+ for (ServiceDiscovery serviceDiscovery : serviceDiscoveries.values()) {
+ serviceDiscovery.destroy();
+ }
+ }
+
+ @Override
+ public void register(ServiceInstance serviceInstance) throws RuntimeException {
+ this.serviceInstance = serviceInstance;
+ serviceDiscoveries.values().forEach(serviceDiscovery -> serviceDiscovery.register(serviceInstance));
+ }
+
+ @Override
+ public void update(ServiceInstance serviceInstance) throws RuntimeException {
+ serviceDiscoveries.values().forEach(serviceDiscovery -> serviceDiscovery.update(serviceInstance));
+ }
+
+ @Override
+ public void unregister(ServiceInstance serviceInstance) throws RuntimeException {
+ serviceDiscoveries.values().forEach(serviceDiscovery -> serviceDiscovery.unregister(serviceInstance));
+ }
+
+ @Override
+ public void addServiceInstancesChangedListener(ServiceInstancesChangedListener listener) throws NullPointerException, IllegalArgumentException {
+ MultiServiceInstancesChangedListener multiListener = new MultiServiceInstancesChangedListener(listener);
+
+ for (String registryKey : serviceDiscoveries.keySet()) {
+ SingleServiceInstancesChangedListener singleListener = new SingleServiceInstancesChangedListener(listener.getServiceNames(), serviceDiscoveries.get(registryKey), multiListener);
+ multiListener.putSingleListener(registryKey, singleListener);
+ serviceDiscoveries.get(registryKey).addServiceInstancesChangedListener(singleListener);
+ }
+ }
+
+ @Override
+ public Page<ServiceInstance> getInstances(String serviceName, int offset, int pageSize, boolean healthyOnly) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
+
+ List<ServiceInstance> serviceInstanceList = new ArrayList<>();
+ for (ServiceDiscovery serviceDiscovery : serviceDiscoveries.values()) {
+ Page<ServiceInstance> serviceInstancePage = serviceDiscovery.getInstances(serviceName, offset, pageSize, healthyOnly);
+ serviceInstanceList.addAll(serviceInstancePage.getData());
+ }
+
+ return new DefaultPage<>(offset, pageSize, serviceInstanceList, serviceInstanceList.size());
+ }
+
+ @Override
+ public Set<String> getServices() {
+ Set<String> services = new HashSet<>();
+ for (ServiceDiscovery serviceDiscovery : serviceDiscoveries.values()) {
+ services.addAll(serviceDiscovery.getServices());
+ }
+ return services;
+ }
+
+ @Override
+ public ServiceInstance getLocalInstance() {
+ return serviceInstance;
+ }
+
+ protected static class MultiServiceInstancesChangedListener implements ConditionalEventListener<ServiceInstancesChangedEvent> {
+ private final ServiceInstancesChangedListener sourceListener;
+ private final Map<String, SingleServiceInstancesChangedListener> singleListenerMap = new ConcurrentHashMap<>();
+
+ public MultiServiceInstancesChangedListener(ServiceInstancesChangedListener sourceListener) {
+ this.sourceListener = sourceListener;
+ }
+
+ @Override
+ public boolean accept(ServiceInstancesChangedEvent event) {
+ return sourceListener.getServiceNames().contains(event.getServiceName());
+ }
+
+ @Override
+ public void onEvent(ServiceInstancesChangedEvent event) {
+ List<ServiceInstance> serviceInstances = new ArrayList<>();
+ for (SingleServiceInstancesChangedListener singleListener : singleListenerMap.values()) {
+ if (null != singleListener.event && null != singleListener.event.getServiceInstances()) {
+ for (ServiceInstance serviceInstance : singleListener.event.getServiceInstances()) {
+ if (!serviceInstances.contains(serviceInstance)) {
+ serviceInstances.add(serviceInstance);
+ }
+ }
+ }
+ }
+
+ sourceListener.onEvent(new ServiceInstancesChangedEvent(event.getServiceName(), serviceInstances));
+ }
+
+ public void putSingleListener(String registryKey, SingleServiceInstancesChangedListener singleListener) {
+ singleListenerMap.put(registryKey, singleListener);
+ }
+ }
+
+ protected static class SingleServiceInstancesChangedListener extends ServiceInstancesChangedListener {
+ private final MultiServiceInstancesChangedListener multiListener;
+ volatile ServiceInstancesChangedEvent event;
+
+ public SingleServiceInstancesChangedListener(Set<String> serviceNames, ServiceDiscovery serviceDiscovery, MultiServiceInstancesChangedListener multiListener) {
+ super(serviceNames, serviceDiscovery);
+ this.multiListener = multiListener;
+ }
+
+ @Override
+ public void onEvent(ServiceInstancesChangedEvent event) {
+ this.event = event;
+ if (multiListener != null) {
+ multiListener.onEvent(event);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleServiceDiscoveryFactory.java
similarity index 63%
copy from dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
copy to dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleServiceDiscoveryFactory.java
index d5b3dbc..9de8d3d 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
+++ b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleServiceDiscoveryFactory.java
@@ -1,36 +1,28 @@
-/*
- * 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;
-
-import org.apache.dubbo.common.Node;
-import org.apache.dubbo.common.URL;
-
-/**
- * Registry. (SPI, Prototype, ThreadSafe)
- *
- * @see org.apache.dubbo.registry.RegistryFactory#getRegistry(URL)
- * @see org.apache.dubbo.registry.support.AbstractRegistry
- */
-public interface Registry extends Node, RegistryService {
- default void reExportRegister(URL url) {
- register(url);
- }
-
- default void reExportUnregister(URL url) {
- unregister(url);
- }
+/*
+ * 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.multiple;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.registry.client.AbstractServiceDiscoveryFactory;
+import org.apache.dubbo.registry.client.ServiceDiscovery;
+
+public class MultipleServiceDiscoveryFactory extends AbstractServiceDiscoveryFactory {
+ @Override
+ protected ServiceDiscovery createDiscovery(URL registryURL) {
+ return new MultipleServiceDiscovery();
+ }
}
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-multiple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscovery b/dubbo-registry/dubbo-registry-multiple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscovery
new file mode 100644
index 0000000..9fc8f6d
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-multiple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscovery
@@ -0,0 +1 @@
+multiple=org.apache.dubbo.registry.multiple.MultipleServiceDiscovery
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-multiple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory b/dubbo-registry/dubbo-registry-multiple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory
new file mode 100644
index 0000000..5565f75
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-multiple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory
@@ -0,0 +1 @@
+multiple=org.apache.dubbo.registry.multiple.MultipleServiceDiscoveryFactory
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-multiple/src/test/java/org/apache/dubbo/registry/multiple/MultipleRegistryTestUtil.java b/dubbo-registry/dubbo-registry-multiple/src/test/java/org/apache/dubbo/registry/multiple/MultipleRegistryTestUtil.java
index a0aeef2..5f5adfa 100644
--- a/dubbo-registry/dubbo-registry-multiple/src/test/java/org/apache/dubbo/registry/multiple/MultipleRegistryTestUtil.java
+++ b/dubbo-registry/dubbo-registry-multiple/src/test/java/org/apache/dubbo/registry/multiple/MultipleRegistryTestUtil.java
@@ -31,7 +31,6 @@ import java.util.Objects;
import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.RegistryConstants.APP_DYNAMIC_CONFIGURATORS_CATEGORY;
-import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.COMPATIBLE_CONFIG_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;
@@ -85,7 +84,7 @@ public class MultipleRegistryTestUtil {
}
private static boolean isValidCategory(URL url) {
- String category = url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);
+ String category = url.getCategory(DEFAULT_CATEGORY);
if ((ROUTERS_CATEGORY.equals(category) || ROUTE_PROTOCOL.equals(url.getProtocol())) ||
PROVIDERS_CATEGORY.equals(category) ||
CONFIGURATORS_CATEGORY.equals(category) || DYNAMIC_CONFIGURATORS_CATEGORY.equals(category) ||
diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java
index 187da71..923401f 100644
--- a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java
+++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java
@@ -17,25 +17,28 @@
package org.apache.dubbo.registry.nacos;
-import com.alibaba.nacos.api.common.Constants;
-import com.google.common.collect.Lists;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.URLBuilder;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.url.component.DubboServiceAddressURL;
import org.apache.dubbo.common.utils.StringUtils;
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.nacos.util.NacosInstanceManageUtil;
import org.apache.dubbo.registry.support.FailbackRegistry;
+import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
+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 com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Arrays;
@@ -140,7 +143,7 @@ public class NacosRegistry extends FailbackRegistry {
Set<String> serviceNames = getServiceNames(url, null);
for (String serviceName : serviceNames) {
List<Instance> instances = namingService.getAllInstances(serviceName,
- getUrl().getParameter(GROUP_KEY, Constants.DEFAULT_GROUP));
+ getUrl().getGroup(Constants.DEFAULT_GROUP));
urls.addAll(buildURLs(url, instances));
}
});
@@ -158,7 +161,7 @@ public class NacosRegistry extends FailbackRegistry {
* in https://github.com/apache/dubbo/issues/5978
*/
execute(namingService -> namingService.registerInstance(serviceName,
- getUrl().getParameter(GROUP_KEY, Constants.DEFAULT_GROUP), instance));
+ getUrl().getGroup(Constants.DEFAULT_GROUP), instance));
}
@Override
@@ -167,7 +170,7 @@ public class NacosRegistry extends FailbackRegistry {
String serviceName = getServiceName(url);
Instance instance = createInstance(url);
namingService.deregisterInstance(serviceName,
- getUrl().getParameter(GROUP_KEY, Constants.DEFAULT_GROUP),
+ getUrl().getGroup(Constants.DEFAULT_GROUP),
instance.getIp()
, instance.getPort());
});
@@ -203,7 +206,7 @@ public class NacosRegistry extends FailbackRegistry {
*/
for (String serviceName : serviceNames) {
List<Instance> instances = namingService.getAllInstances(serviceName,
- getUrl().getParameter(GROUP_KEY, Constants.DEFAULT_GROUP));
+ getUrl().getGroup(Constants.DEFAULT_GROUP));
NacosInstanceManageUtil.initOrRefreshServiceInstanceList(serviceName, instances);
allCorrespondingInstanceList.addAll(instances);
}
@@ -215,7 +218,7 @@ public class NacosRegistry extends FailbackRegistry {
List<Instance> instances = new LinkedList<>();
for (String serviceName : serviceNames) {
instances.addAll(namingService.getAllInstances(serviceName
- , getUrl().getParameter(GROUP_KEY, Constants.DEFAULT_GROUP)));
+ , getUrl().getGroup(Constants.DEFAULT_GROUP)));
notifySubscriber(url, listener, instances);
subscribeEventListener(serviceName, url, listener);
}
@@ -295,7 +298,7 @@ public class NacosRegistry extends FailbackRegistry {
execute(namingService -> {
serviceNames.addAll(namingService.getServicesOfServer(1, Integer.MAX_VALUE,
- getUrl().getParameter(GROUP_KEY, Constants.DEFAULT_GROUP)).getData()
+ getUrl().getGroup(Constants.DEFAULT_GROUP)).getData()
.stream()
.map(NacosServiceName::new)
.filter(serviceName::isCompatible)
@@ -375,7 +378,7 @@ public class NacosRegistry extends FailbackRegistry {
int pageIndex = 1;
ListView<String> listView = namingService.getServicesOfServer(pageIndex, PAGINATION_SIZE,
- getUrl().getParameter(GROUP_KEY, Constants.DEFAULT_GROUP));
+ getUrl().getGroup(Constants.DEFAULT_GROUP));
// First page data
List<String> firstPageData = listView.getData();
// Append first page into list
@@ -392,7 +395,7 @@ public class NacosRegistry extends FailbackRegistry {
// If more than 1 page
while (pageIndex < pageNumbers) {
listView = namingService.getServicesOfServer(++pageIndex, PAGINATION_SIZE,
- getUrl().getParameter(GROUP_KEY, Constants.DEFAULT_GROUP));
+ getUrl().getGroup(Constants.DEFAULT_GROUP));
serviceNames.addAll(listView.getData());
}
@@ -407,9 +410,9 @@ public class NacosRegistry extends FailbackRegistry {
final String targetServiceInterface = url.getServiceInterface();
- final String targetVersion = url.getParameter(VERSION_KEY, "");
+ final String targetVersion = url.getVersion("");
- final String targetGroup = url.getParameter(GROUP_KEY, "");
+ final String targetGroup = url.getGroup("");
filterData(serviceNames, serviceName -> {
// split service name to segments
@@ -478,7 +481,7 @@ public class NacosRegistry extends FailbackRegistry {
List<URL> urls = new LinkedList<>();
if (instances != null && !instances.isEmpty()) {
for (Instance instance : instances) {
- URL url = buildURL(instance);
+ URL url = buildURL(consumerURL, instance);
if (UrlUtils.isMatch(consumerURL, url)) {
urls.add(url);
}
@@ -489,26 +492,9 @@ public class NacosRegistry extends FailbackRegistry {
private void subscribeEventListener(String serviceName, final URL url, final NotifyListener listener)
throws NacosException {
- EventListener eventListener = event -> {
- if (event instanceof NamingEvent) {
- NamingEvent e = (NamingEvent) event;
- List<Instance> instances = e.getInstances();
-
-
- if (isServiceNamesWithCompatibleMode(url)) {
- /**
- * Get all instances with corresponding 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
- */
- NacosInstanceManageUtil.initOrRefreshServiceInstanceList(serviceName, instances);
- instances = NacosInstanceManageUtil.getAllCorrespondingServiceInstanceList(serviceName);
- }
-
- notifySubscriber(url, listener, instances);
- }
- };
+ EventListener eventListener = new RegistryChildListenerImpl(serviceName, url, listener);
namingService.subscribe(serviceName,
- getUrl().getParameter(GROUP_KEY, Constants.DEFAULT_GROUP),
+ getUrl().getGroup(Constants.DEFAULT_GROUP),
eventListener);
}
@@ -540,20 +526,21 @@ public class NacosRegistry extends FailbackRegistry {
ALL_SUPPORTED_CATEGORIES : Arrays.asList(DEFAULT_CATEGORY);
}
- private URL buildURL(Instance instance) {
+ private URL buildURL(URL consumerURL, Instance instance) {
Map<String, String> metadata = instance.getMetadata();
String protocol = metadata.get(PROTOCOL_KEY);
String path = metadata.get(PATH_KEY);
- return new URL(protocol,
+ URL url = new URL(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.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);
+ 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());
@@ -571,7 +558,7 @@ public class NacosRegistry extends FailbackRegistry {
}
private String getServiceName(URL url) {
- return getServiceName(url, url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY));
+ return getServiceName(url, url.getCategory(DEFAULT_CATEGORY));
}
private String getServiceName(URL url, String category) {
@@ -626,4 +613,35 @@ public class NacosRegistry extends FailbackRegistry {
void callback(NamingService namingService) throws NacosException;
}
+
+ private class RegistryChildListenerImpl implements EventListener {
+ private RegistryNotifier notifier;
+
+ public RegistryChildListenerImpl(String serviceName, URL consumerUrl, NotifyListener listener) {
+ notifier = new RegistryNotifier(NacosRegistry.this) {
+ @Override
+ protected void doNotify(Object rawAddresses) {
+ List<Instance> instances = (List<Instance>) rawAddresses;
+ if (isServiceNamesWithCompatibleMode(consumerUrl)) {
+ /**
+ * Get all instances with corresponding 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
+ */
+ NacosInstanceManageUtil.initOrRefreshServiceInstanceList(serviceName, instances);
+ instances = NacosInstanceManageUtil.getAllCorrespondingServiceInstanceList(serviceName);
+ }
+ NacosRegistry.this.notifySubscriber(consumerUrl, listener, instances);
+ }
+ };
+ }
+
+ @Override
+ public void onEvent(Event event) {
+ if (event instanceof NamingEvent) {
+ NamingEvent e = (NamingEvent) event;
+ notifier.notify(e.getInstances());
+ }
+ }
+ }
+
}
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceName.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceName.java
index 27c45ee..03a74df 100644
--- a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceName.java
+++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceName.java
@@ -22,10 +22,7 @@ import org.apache.dubbo.common.utils.StringUtils;
import java.util.Arrays;
import java.util.Objects;
-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.VERSION_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;
import static org.apache.dubbo.common.utils.StringUtils.isBlank;
@@ -67,9 +64,9 @@ public class NacosServiceName {
public NacosServiceName(URL url) {
serviceInterface = url.getParameter(INTERFACE_KEY);
- category = isConcrete(serviceInterface) ? DEFAULT_CATEGORY : url.getParameter(CATEGORY_KEY);
- version = url.getParameter(VERSION_KEY, DEFAULT_PARAM_VALUE);
- group = url.getParameter(GROUP_KEY, DEFAULT_PARAM_VALUE);
+ category = isConcrete(serviceInterface) ? DEFAULT_CATEGORY : url.getCategory();
+ version = url.getVersion(DEFAULT_PARAM_VALUE);
+ group = url.getGroup(DEFAULT_PARAM_VALUE);
value = toValue();
}
diff --git a/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperRegistry.java b/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperRegistry.java
index 51fa4aa..ae22530 100644
--- a/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperRegistry.java
+++ b/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperRegistry.java
@@ -17,15 +17,14 @@
package org.apache.dubbo.registry.zookeeper;
import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.URLBuilder;
-import org.apache.dubbo.common.URLStrParser;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.ConcurrentHashSet;
import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.registry.NotifyListener;
-import org.apache.dubbo.registry.support.FailbackRegistry;
+import org.apache.dubbo.registry.RegistryNotifier;
+import org.apache.dubbo.registry.support.CacheableFailbackRegistry;
import org.apache.dubbo.remoting.Constants;
import org.apache.dubbo.remoting.zookeeper.ChildListener;
import org.apache.dubbo.remoting.zookeeper.StateListener;
@@ -40,26 +39,22 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CountDownLatch;
import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
-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_SEPARATOR;
-import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_SEPARATOR_ENCODED;
-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.DYNAMIC_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;
/**
* ZookeeperRegistry
- *
*/
-public class ZookeeperRegistry extends FailbackRegistry {
+public class ZookeeperRegistry extends CacheableFailbackRegistry {
private final static Logger logger = LoggerFactory.getLogger(ZookeeperRegistry.class);
@@ -78,7 +73,7 @@ public class ZookeeperRegistry extends FailbackRegistry {
if (url.isAnyHost()) {
throw new IllegalStateException("registry address == null");
}
- String group = url.getParameter(GROUP_KEY, DEFAULT_ROOT);
+ String group = url.getGroup(DEFAULT_ROOT);
if (!group.startsWith(PATH_SEPARATOR)) {
group = PATH_SEPARATOR + group;
}
@@ -168,10 +163,11 @@ public class ZookeeperRegistry extends FailbackRegistry {
}
}
} else {
+ CountDownLatch latch = new CountDownLatch(1);
List<URL> urls = new ArrayList<>();
for (String path : toCategoriesPath(url)) {
ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.computeIfAbsent(url, k -> new ConcurrentHashMap<>());
- ChildListener zkListener = listeners.computeIfAbsent(listener, k -> (parentPath, currentChilds) -> ZookeeperRegistry.this.notify(url, k, toUrlsWithEmpty(url, parentPath, currentChilds)));
+ ChildListener zkListener = listeners.computeIfAbsent(listener, k -> new RegistryChildListenerImpl(url, path, k, latch));
zkClient.create(path, false);
List<String> children = zkClient.addChildListener(path, zkListener);
if (children != null) {
@@ -179,6 +175,8 @@ public class ZookeeperRegistry extends FailbackRegistry {
}
}
notify(url, listener, urls);
+ // tells the listener to run only after the sync notification of main thread finishes.
+ latch.countDown();
}
} catch (Throwable e) {
throw new RpcException("Failed to subscribe " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
@@ -187,9 +185,9 @@ public class ZookeeperRegistry extends FailbackRegistry {
@Override
public void doUnsubscribe(URL url, NotifyListener listener) {
- ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
+ ConcurrentMap<NotifyListener, org.apache.dubbo.remoting.zookeeper.ChildListener> listeners = zkListeners.get(url);
if (listeners != null) {
- ChildListener zkListener = listeners.get(listener);
+ org.apache.dubbo.remoting.zookeeper.ChildListener zkListener = listeners.get(listener);
if (zkListener != null) {
if (ANY_VALUE.equals(url.getServiceInterface())) {
String root = toRootPath();
@@ -243,10 +241,10 @@ public class ZookeeperRegistry extends FailbackRegistry {
private String[] toCategoriesPath(URL url) {
String[] categories;
- if (ANY_VALUE.equals(url.getParameter(CATEGORY_KEY))) {
+ if (ANY_VALUE.equals(url.getCategory())) {
categories = new String[]{PROVIDERS_CATEGORY, CONSUMERS_CATEGORY, ROUTERS_CATEGORY, CONFIGURATORS_CATEGORY};
} else {
- categories = url.getParameter(CATEGORY_KEY, new String[]{DEFAULT_CATEGORY});
+ categories = url.getCategory(new String[]{DEFAULT_CATEGORY});
}
String[] paths = new String[categories.length];
for (int i = 0; i < categories.length; i++) {
@@ -256,42 +254,13 @@ public class ZookeeperRegistry extends FailbackRegistry {
}
private String toCategoryPath(URL url) {
- return toServicePath(url) + PATH_SEPARATOR + url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);
+ return toServicePath(url) + PATH_SEPARATOR + url.getCategory(DEFAULT_CATEGORY);
}
private String toUrlPath(URL url) {
return toCategoryPath(url) + PATH_SEPARATOR + URL.encode(url.toFullString());
}
- private List<URL> toUrlsWithoutEmpty(URL consumer, List<String> providers) {
- List<URL> urls = new ArrayList<>();
- if (CollectionUtils.isNotEmpty(providers)) {
- for (String provider : providers) {
- if (provider.contains(PROTOCOL_SEPARATOR_ENCODED)) {
- URL url = URLStrParser.parseEncodedStr(provider);
- if (UrlUtils.isMatch(consumer, url)) {
- urls.add(url);
- }
- }
- }
- }
- return urls;
- }
-
- private List<URL> toUrlsWithEmpty(URL consumer, String path, List<String> providers) {
- List<URL> urls = toUrlsWithoutEmpty(consumer, providers);
- if (urls == null || urls.isEmpty()) {
- int i = path.lastIndexOf(PATH_SEPARATOR);
- String category = i < 0 ? path : path.substring(i + 1);
- URL empty = URLBuilder.from(consumer)
- .setProtocol(EMPTY_PROTOCOL)
- .addParameter(CATEGORY_KEY, category)
- .build();
- urls.add(empty);
- }
- return urls;
- }
-
/**
* When zookeeper connection recovered from a connection loss, it need to fetch the latest provider list.
* re-register watcher is only a side effect and is not mandate.
@@ -312,4 +281,53 @@ public class ZookeeperRegistry extends FailbackRegistry {
}
}
+ @Override
+ protected boolean isMatch(URL subscribeUrl, URL providerUrl) {
+ return UrlUtils.isMatch(subscribeUrl, providerUrl);
+ }
+
+ private class RegistryChildListenerImpl implements ChildListener {
+ private RegistryNotifier notifier;
+ private long lastExecuteTime;
+ private CountDownLatch latch;
+
+ public RegistryChildListenerImpl(URL consumerUrl, String path, NotifyListener listener, CountDownLatch latch) {
+ this.latch = latch;
+ notifier = new RegistryNotifier(ZookeeperRegistry.this) {
+ @Override
+ public void notify(Object rawAddresses) {
+ int delayTime = getRegistry().getDelay();
+ if (delayTime <= 0) {
+ this.doNotify(rawAddresses);
+ } else {
+ long interval = delayTime - (System.currentTimeMillis() - lastExecuteTime);
+ if (interval > 0) {
+ try {
+ Thread.sleep(interval);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ lastExecuteTime = System.currentTimeMillis();
+ this.doNotify(rawAddresses);
+ }
+ }
+
+ @Override
+ protected void doNotify(Object rawAddresses) {
+ ZookeeperRegistry.this.notify(consumerUrl, listener, ZookeeperRegistry.this.toUrlsWithEmpty(consumerUrl, path, (List<String>) rawAddresses));
+ }
+ };
+ }
+
+ @Override
+ public void childChanged(String path, List<String> children) {
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ logger.warn("Zookeeper children listener thread was interrupted unexpectedly, may cause race condition with the main thread.");
+ }
+ notifier.notify(children);
+ }
+ }
}
diff --git a/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscovery.java b/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscovery.java
index d5f4f3d..80b7d2a 100644
--- a/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscovery.java
+++ b/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscovery.java
@@ -24,7 +24,6 @@ import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.DefaultPage;
import org.apache.dubbo.common.utils.Page;
import org.apache.dubbo.event.EventDispatcher;
-import org.apache.dubbo.registry.client.AbstractServiceDiscovery;
import org.apache.dubbo.registry.client.ServiceDiscovery;
import org.apache.dubbo.registry.client.ServiceInstance;
import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;
@@ -52,7 +51,7 @@ import static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkUtils.bui
* Zookeeper {@link ServiceDiscovery} implementation based on
* <a href="https://curator.apache.org/curator-x-discovery/index.html">Apache Curator X Discovery</a>
*/
-public class ZookeeperServiceDiscovery extends AbstractServiceDiscovery {
+public class ZookeeperServiceDiscovery implements ServiceDiscovery {
private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -66,6 +65,8 @@ public class ZookeeperServiceDiscovery extends AbstractServiceDiscovery {
private org.apache.curator.x.discovery.ServiceDiscovery<ZookeeperInstance> serviceDiscovery;
+ private ServiceInstance serviceInstance;
+
/**
* The Key is watched Zookeeper path, the value is an instance of {@link CuratorWatcher}
*/
@@ -89,6 +90,11 @@ public class ZookeeperServiceDiscovery extends AbstractServiceDiscovery {
serviceDiscovery.close();
}
+ @Override
+ public ServiceInstance getLocalInstance() {
+ return serviceInstance;
+ }
+
public void register(ServiceInstance serviceInstance) throws RuntimeException {
this.serviceInstance = serviceInstance;
doInServiceRegistry(serviceDiscovery -> {
@@ -129,25 +135,30 @@ public class ZookeeperServiceDiscovery extends AbstractServiceDiscovery {
List<ServiceInstance> serviceInstances = new LinkedList<>();
- List<String> serviceIds = new LinkedList<>(curatorFramework.getChildren().forPath(p));
+ int totalSize = 0;
+ try {
+ List<String> serviceIds = new LinkedList<>(curatorFramework.getChildren().forPath(p));
- int totalSize = serviceIds.size();
+ totalSize = serviceIds.size();
- Iterator<String> iterator = serviceIds.iterator();
+ Iterator<String> iterator = serviceIds.iterator();
- for (int i = 0; i < offset; i++) {
- if (iterator.hasNext()) { // remove the elements from 0 to offset
- iterator.next();
- iterator.remove();
+ for (int i = 0; i < offset; i++) {
+ if (iterator.hasNext()) { // remove the elements from 0 to offset
+ iterator.next();
+ iterator.remove();
+ }
}
- }
- for (int i = 0; i < pageSize; i++) {
- if (iterator.hasNext()) {
- String serviceId = iterator.next();
- ServiceInstance serviceInstance = build(serviceDiscovery.queryForInstance(serviceName, serviceId));
- serviceInstances.add(serviceInstance);
+ for (int i = 0; i < pageSize; i++) {
+ if (iterator.hasNext()) {
+ String serviceId = iterator.next();
+ ServiceInstance serviceInstance = build(serviceDiscovery.queryForInstance(serviceName, serviceId));
+ serviceInstances.add(serviceInstance);
+ }
}
+ } catch (KeeperException.NoNodeException e) {
+ logger.warn(p + " path not exist.", e);
}
return new DefaultPage<>(offset, pageSize, serviceInstances, totalSize);
@@ -180,6 +191,17 @@ public class ZookeeperServiceDiscovery extends AbstractServiceDiscovery {
protected void registerServiceWatcher(String serviceName, ServiceInstancesChangedListener listener) {
String path = buildServicePath(serviceName);
+ try {
+ curatorFramework.create().forPath(path);
+ } catch (KeeperException.NodeExistsException e) {
+ // ignored
+ if (logger.isDebugEnabled()) {
+ logger.debug(e);
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("registerServiceWatcher create path=" + path + " fail.", e);
+ }
+
CuratorWatcher watcher = watcherCaches.computeIfAbsent(path, key ->
new ZookeeperServiceDiscoveryChangeWatcher(this, serviceName, listener));
try {
diff --git a/dubbo-registry/dubbo-registry-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory b/dubbo-registry/dubbo-registry-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory
new file mode 100644
index 0000000..12262ad
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory
@@ -0,0 +1 @@
+zookeeper=org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscoveryFactory
\ No newline at end of file
diff --git a/dubbo-remoting/dubbo-remoting-http/src/main/java/org/apache/dubbo/remoting/http/tomcat/TomcatHttpServer.java b/dubbo-remoting/dubbo-remoting-http/src/main/java/org/apache/dubbo/remoting/http/tomcat/TomcatHttpServer.java
index 9fd9652..0711590 100755
--- a/dubbo-remoting/dubbo-remoting-http/src/main/java/org/apache/dubbo/remoting/http/tomcat/TomcatHttpServer.java
+++ b/dubbo-remoting/dubbo-remoting-http/src/main/java/org/apache/dubbo/remoting/http/tomcat/TomcatHttpServer.java
@@ -51,21 +51,23 @@ public class TomcatHttpServer extends AbstractHttpServer {
String baseDir = new File(System.getProperty("java.io.tmpdir")).getAbsolutePath();
tomcat = new Tomcat();
- Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
+ Connector connector = tomcat.getConnector();
connector.setPort(url.getPort());
connector.setProperty("maxThreads", String.valueOf(url.getParameter(THREADS_KEY, DEFAULT_THREADS)));
connector.setProperty("maxConnections", String.valueOf(url.getParameter(ACCEPTS_KEY, -1)));
connector.setProperty("URIEncoding", "UTF-8");
connector.setProperty("connectionTimeout", "60000");
connector.setProperty("maxKeepAliveRequests", "-1");
- tomcat.setConnector(connector);
tomcat.setBaseDir(baseDir);
tomcat.setPort(url.getPort());
Context context = tomcat.addContext("/", baseDir);
Tomcat.addServlet(context, "dispatcher", new DispatcherServlet());
- context.addServletMapping("/*", "dispatcher");
+ // Issue : https://github.com/apache/dubbo/issues/6418
+ // addServletMapping method will be removed since Tomcat 9
+ // context.addServletMapping("/*", "dispatcher");
+ context.addServletMappingDecoded("/*", "dispatcher");
ServletManager.getInstance().addServletContext(url.getPort(), context.getServletContext());
// tell tomcat to fail on startup failures.
diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java
index cbb3747..775d291 100644
--- a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java
+++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java
@@ -62,4 +62,6 @@ public interface ZookeeperClient {
String getContent(String path);
+ boolean checkExists(String path);
+
}
diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperClient.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperClient.java
index 6b7f8e2..42fe5c9 100644
--- a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperClient.java
+++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperClient.java
@@ -199,7 +199,7 @@ public abstract class AbstractZookeeperClient<TargetDataListener, TargetChildLis
protected abstract void createEphemeral(String path, String data);
- protected abstract boolean checkExists(String path);
+ public abstract boolean checkExists(String path);
protected abstract TargetChildListener createTargetChildListener(String path, ChildListener listener);
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/FilterChainBuilder.java
similarity index 60%
copy from dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
copy to dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/FilterChainBuilder.java
index d5b3dbc..b8a7ac5 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/FilterChainBuilder.java
@@ -1,36 +1,24 @@
-/*
- * 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;
-
-import org.apache.dubbo.common.Node;
-import org.apache.dubbo.common.URL;
-
-/**
- * Registry. (SPI, Prototype, ThreadSafe)
- *
- * @see org.apache.dubbo.registry.RegistryFactory#getRegistry(URL)
- * @see org.apache.dubbo.registry.support.AbstractRegistry
- */
-public interface Registry extends Node, RegistryService {
- default void reExportRegister(URL url) {
- register(url);
- }
-
- default void reExportUnregister(URL url) {
- unregister(url);
- }
-}
\ No newline at end of file
+/*
+ * 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.rpc;
+
+import org.apache.dubbo.common.extension.SPI;
+
+@SPI("default")
+public interface FilterChainBuilder {
+ <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group);
+}
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java
index 8077067..36ae6a8 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java
@@ -35,11 +35,8 @@ import java.util.concurrent.Future;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_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.SIDE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.rpc.Constants.ASYNC_KEY;
import static org.apache.dubbo.rpc.Constants.RETURN_KEY;
@@ -237,7 +234,7 @@ public class RpcContext {
* @return consumer side.
*/
public boolean isConsumerSide() {
- return getUrl().getParameter(SIDE_KEY, PROVIDER_SIDE).equals(CONSUMER_SIDE);
+ return getUrl().getSide(PROVIDER_SIDE).equals(CONSUMER_SIDE);
}
/**
@@ -806,14 +803,14 @@ public class RpcContext {
if (consumerUrl == null) {
return null;
}
- return consumerUrl.getParameter(GROUP_KEY);
+ return consumerUrl.getGroup();
}
public String getVersion() {
if (consumerUrl == null) {
return null;
}
- return consumerUrl.getParameter(VERSION_KEY);
+ return consumerUrl.getVersion();
}
public String getInterfaceName() {
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java
index be830d7..ba6f9b6 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java
@@ -94,10 +94,10 @@ public class RpcInvocation implements Invocation, Serializable {
setAttachment(INTERFACE_KEY, url.getParameter(INTERFACE_KEY));
}
if (url.hasParameter(GROUP_KEY)) {
- setAttachment(GROUP_KEY, url.getParameter(GROUP_KEY));
+ setAttachment(GROUP_KEY, url.getGroup());
}
if (url.hasParameter(VERSION_KEY)) {
- setAttachment(VERSION_KEY, url.getParameter(VERSION_KEY, "0.0.0"));
+ setAttachment(VERSION_KEY, url.getVersion("0.0.0"));
}
if (url.hasParameter(TIMEOUT_KEY)) {
setAttachment(TIMEOUT_KEY, url.getParameter(TIMEOUT_KEY));
@@ -106,7 +106,7 @@ public class RpcInvocation implements Invocation, Serializable {
setAttachment(TOKEN_KEY, url.getParameter(TOKEN_KEY));
}
if (url.hasParameter(APPLICATION_KEY)) {
- setAttachment(APPLICATION_KEY, url.getParameter(APPLICATION_KEY));
+ setAttachment(APPLICATION_KEY, url.getApplication());
}
}
this.targetServiceUniqueName = invocation.getTargetServiceUniqueName();
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/AccessLogFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/AccessLogFilter.java
index 63de8c4..1cf09fb 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/AccessLogFilter.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/AccessLogFilter.java
@@ -43,9 +43,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.rpc.Constants.ACCESS_LOG_KEY;
/**
@@ -170,8 +168,8 @@ public class AccessLogFilter implements Filter {
AccessLogData logData = AccessLogData.newLogData();
logData.setServiceName(invoker.getInterface().getName());
logData.setMethodName(inv.getMethodName());
- logData.setVersion(invoker.getUrl().getParameter(VERSION_KEY));
- logData.setGroup(invoker.getUrl().getParameter(GROUP_KEY));
+ logData.setVersion(invoker.getUrl().getVersion());
+ logData.setGroup(invoker.getUrl().getGroup());
logData.setInvocationTime(new Date());
logData.setTypes(inv.getParameterTypes());
logData.setArguments(inv.getArguments());
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java
index 5aad186..ad14831 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java
@@ -28,7 +28,6 @@ import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.TimeoutCountDown;
-import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIME_COUNTDOWN_KEY;
@@ -46,12 +45,9 @@ public class ConsumerContextFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
RpcContext context = RpcContext.getContext();
- context.setInvoker(invoker)
- .setInvocation(invocation)
+ context.setInvocation(invocation)
.setLocalAddress(NetUtils.getLocalHost(), 0)
- .setRemoteAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort())
- .setRemoteApplicationName(invoker.getUrl().getParameter(REMOTE_APPLICATION_KEY))
- .setAttachment(REMOTE_APPLICATION_KEY, invoker.getUrl().getParameter(APPLICATION_KEY));
+ .setAttachment(REMOTE_APPLICATION_KEY, invoker.getUrl().getApplication());
if (invocation instanceof RpcInvocation) {
((RpcInvocation) invocation).setInvoker(invoker);
}
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java
index 94c7b79..f8a5ac9 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java
@@ -42,7 +42,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.atomic.AtomicBoolean;
/**
* This Invoker works on Consumer side.
@@ -59,7 +58,7 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
private volatile boolean available = true;
- private AtomicBoolean destroyed = new AtomicBoolean(false);
+ private boolean destroyed = false;
public AbstractInvoker(Class<T> type, URL url) {
this(type, url, (Map<String, Object>) null);
@@ -116,14 +115,12 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
@Override
public void destroy() {
- if (!destroyed.compareAndSet(false, true)) {
- return;
- }
+ this.destroyed = true;
setAvailable(false);
}
public boolean isDestroyed() {
- return destroyed.get();
+ return destroyed;
}
@Override
@@ -134,7 +131,7 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
@Override
public Result invoke(Invocation inv) throws RpcException {
// if invoker is destroyed due to address refresh from registry, let's allow the current invoke to proceed
- if (destroyed.get()) {
+ if (isDestroyed()) {
logger.warn("Invoker for service " + this + " on consumer " + NetUtils.getLocalHost() + " is destroyed, "
+ ", dubbo version is " + Version.getVersion() + ", this invoker should not be used any longer");
}
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProtocol.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProtocol.java
index d27fcbb..903cd27 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProtocol.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProtocol.java
@@ -36,9 +36,6 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
-
/**
* abstract ProtocolSupport.
*/
@@ -58,7 +55,7 @@ public abstract class AbstractProtocol implements Protocol {
protected static String serviceKey(URL url) {
int port = url.getParameter(Constants.BIND_PORT_KEY, url.getPort());
- return serviceKey(port, url.getPath(), url.getParameter(VERSION_KEY), url.getParameter(GROUP_KEY));
+ return serviceKey(port, url.getPath(), url.getVersion(), url.getGroup());
}
protected static String serviceKey(int port, String serviceName, String serviceVersion, String serviceGroup) {
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolFilterWrapper.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolFilterWrapper.java
index 74ac50c..24fcc8a 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolFilterWrapper.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolFilterWrapper.java
@@ -22,18 +22,14 @@ import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.rpc.Exporter;
-import org.apache.dubbo.rpc.Filter;
-import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.FilterChainBuilder;
import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.ListenableFilter;
import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.ProtocolServer;
-import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;
import java.util.List;
-import static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.SERVICE_FILTER_KEY;
/**
@@ -43,6 +39,8 @@ import static org.apache.dubbo.common.constants.CommonConstants.SERVICE_FILTER_K
public class ProtocolFilterWrapper implements Protocol {
private final Protocol protocol;
+ private static final FilterChainBuilder builder
+ = ExtensionLoader.getExtensionLoader(FilterChainBuilder.class).getDefaultExtension();
public ProtocolFilterWrapper(Protocol protocol) {
if (protocol == null) {
@@ -51,97 +49,6 @@ public class ProtocolFilterWrapper implements Protocol {
this.protocol = protocol;
}
- private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
- Invoker<T> last = invoker;
- List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
-
- if (!filters.isEmpty()) {
- for (int i = filters.size() - 1; i >= 0; i--) {
- final Filter filter = filters.get(i);
- final Invoker<T> next = last;
- last = new Invoker<T>() {
-
- @Override
- public Class<T> getInterface() {
- return invoker.getInterface();
- }
-
- @Override
- public URL getUrl() {
- return invoker.getUrl();
- }
-
- @Override
- public boolean isAvailable() {
- return invoker.isAvailable();
- }
-
- @Override
- public Result invoke(Invocation invocation) throws RpcException {
- Result asyncResult;
- try {
- asyncResult = filter.invoke(next, invocation);
- } catch (Exception e) {
- if (filter instanceof ListenableFilter) {
- ListenableFilter listenableFilter = ((ListenableFilter) filter);
- try {
- Filter.Listener listener = listenableFilter.listener(invocation);
- if (listener != null) {
- listener.onError(e, invoker, invocation);
- }
- } finally {
- listenableFilter.removeListener(invocation);
- }
- } else if (filter instanceof Filter.Listener) {
- Filter.Listener listener = (Filter.Listener) filter;
- listener.onError(e, invoker, invocation);
- }
- throw e;
- } finally {
-
- }
- return asyncResult.whenCompleteWithContext((r, t) -> {
- if (filter instanceof ListenableFilter) {
- ListenableFilter listenableFilter = ((ListenableFilter) filter);
- Filter.Listener listener = listenableFilter.listener(invocation);
- try {
- if (listener != null) {
- if (t == null) {
- listener.onResponse(r, invoker, invocation);
- } else {
- listener.onError(t, invoker, invocation);
- }
- }
- } finally {
- listenableFilter.removeListener(invocation);
- }
- } else if (filter instanceof Filter.Listener) {
- Filter.Listener listener = (Filter.Listener) filter;
- if (t == null) {
- listener.onResponse(r, invoker, invocation);
- } else {
- listener.onError(t, invoker, invocation);
- }
- }
- });
- }
-
- @Override
- public void destroy() {
- invoker.destroy();
- }
-
- @Override
- public String toString() {
- return invoker.toString();
- }
- };
- }
- }
-
- return last;
- }
-
@Override
public int getDefaultPort() {
return protocol.getDefaultPort();
@@ -152,7 +59,7 @@ public class ProtocolFilterWrapper implements Protocol {
if (UrlUtils.isRegistry(invoker.getUrl())) {
return protocol.export(invoker);
}
- return protocol.export(buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER));
+ return protocol.export(builder.buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER));
}
@Override
@@ -160,7 +67,7 @@ public class ProtocolFilterWrapper implements Protocol {
if (UrlUtils.isRegistry(url)) {
return protocol.refer(type, url);
}
- return buildInvokerChain(protocol.refer(type, url), REFERENCE_FILTER_KEY, CommonConstants.CONSUMER);
+ return protocol.refer(type, url);
}
@Override
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolListenerWrapper.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolListenerWrapper.java
index af943c3..351024a 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolListenerWrapper.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolListenerWrapper.java
@@ -1,89 +1,96 @@
-/*
- * 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.rpc.protocol;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.Activate;
-import org.apache.dubbo.common.extension.ExtensionLoader;
-import org.apache.dubbo.common.utils.UrlUtils;
-import org.apache.dubbo.rpc.Exporter;
-import org.apache.dubbo.rpc.ExporterListener;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.InvokerListener;
-import org.apache.dubbo.rpc.Protocol;
-import org.apache.dubbo.rpc.ProtocolServer;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.listener.ListenerExporterWrapper;
-import org.apache.dubbo.rpc.listener.ListenerInvokerWrapper;
-
-import java.util.Collections;
-import java.util.List;
-
-import static org.apache.dubbo.common.constants.CommonConstants.EXPORTER_LISTENER_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.INVOKER_LISTENER_KEY;
-
-/**
- * ListenerProtocol
- */
-@Activate(order = 200)
-public class ProtocolListenerWrapper implements Protocol {
-
- private final Protocol protocol;
-
- public ProtocolListenerWrapper(Protocol protocol) {
- if (protocol == null) {
- throw new IllegalArgumentException("protocol == null");
- }
- this.protocol = protocol;
- }
-
- @Override
- public int getDefaultPort() {
- return protocol.getDefaultPort();
- }
-
- @Override
- public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
- if (UrlUtils.isRegistry(invoker.getUrl())) {
- return protocol.export(invoker);
- }
- return new ListenerExporterWrapper<T>(protocol.export(invoker),
- Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
- .getActivateExtension(invoker.getUrl(), EXPORTER_LISTENER_KEY)));
- }
-
- @Override
- public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
- if (UrlUtils.isRegistry(url)) {
- return protocol.refer(type, url);
- }
- return new ListenerInvokerWrapper<T>(protocol.refer(type, url),
- Collections.unmodifiableList(
- ExtensionLoader.getExtensionLoader(InvokerListener.class)
- .getActivateExtension(url, INVOKER_LISTENER_KEY)));
- }
-
- @Override
- public void destroy() {
- protocol.destroy();
- }
-
- @Override
- public List<ProtocolServer> getServers() {
- return protocol.getServers();
- }
-}
+/*
+ * 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.rpc.protocol;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.common.utils.UrlUtils;
+import org.apache.dubbo.rpc.Exporter;
+import org.apache.dubbo.rpc.ExporterListener;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.InvokerListener;
+import org.apache.dubbo.rpc.Protocol;
+import org.apache.dubbo.rpc.ProtocolServer;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.listener.ListenerExporterWrapper;
+import org.apache.dubbo.rpc.listener.ListenerInvokerWrapper;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.apache.dubbo.common.constants.CommonConstants.EXPORTER_LISTENER_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.FILTER_BUILDER_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.INVOKER_LISTENER_KEY;
+
+/**
+ * ListenerProtocol
+ */
+@Activate(order = 200)
+public class ProtocolListenerWrapper implements Protocol {
+
+ private final Protocol protocol;
+
+ public ProtocolListenerWrapper(Protocol protocol) {
+ if (protocol == null) {
+ throw new IllegalArgumentException("protocol == null");
+ }
+ this.protocol = protocol;
+ }
+
+ @Override
+ public int getDefaultPort() {
+ return protocol.getDefaultPort();
+ }
+
+ @Override
+ public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
+ if (UrlUtils.isRegistry(invoker.getUrl())) {
+ return protocol.export(invoker);
+ }
+ return new ListenerExporterWrapper<T>(protocol.export(invoker),
+ Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
+ .getActivateExtension(invoker.getUrl(), EXPORTER_LISTENER_KEY)));
+ }
+
+ @Override
+ public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
+ if (UrlUtils.isRegistry(url)) {
+ return protocol.refer(type, url);
+ }
+
+ Invoker<T> invoker = protocol.refer(type, url);
+ if (StringUtils.isEmpty(url.getParameter(FILTER_BUILDER_KEY))) {
+ invoker = new ListenerInvokerWrapper<>(invoker,
+ Collections.unmodifiableList(
+ ExtensionLoader.getExtensionLoader(InvokerListener.class)
+ .getActivateExtension(url, INVOKER_LISTENER_KEY)));
+ }
+ return invoker;
+ }
+
+ @Override
+ public void destroy() {
+ protocol.destroy();
+ }
+
+ @Override
+ public List<ProtocolServer> getServers() {
+ return protocol.getServers();
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolFilterWrapper.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/DefaultFilterChainBuilder.java
similarity index 72%
copy from dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolFilterWrapper.java
copy to dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/DefaultFilterChainBuilder.java
index 74ac50c..24b350b 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolFilterWrapper.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/DefaultFilterChainBuilder.java
@@ -1,176 +1,125 @@
-/*
- * 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.rpc.protocol;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.constants.CommonConstants;
-import org.apache.dubbo.common.extension.Activate;
-import org.apache.dubbo.common.extension.ExtensionLoader;
-import org.apache.dubbo.common.utils.UrlUtils;
-import org.apache.dubbo.rpc.Exporter;
-import org.apache.dubbo.rpc.Filter;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.ListenableFilter;
-import org.apache.dubbo.rpc.Protocol;
-import org.apache.dubbo.rpc.ProtocolServer;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcException;
-
-import java.util.List;
-
-import static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.SERVICE_FILTER_KEY;
-
-/**
- * ListenerProtocol
- */
-@Activate(order = 100)
-public class ProtocolFilterWrapper implements Protocol {
-
- private final Protocol protocol;
-
- public ProtocolFilterWrapper(Protocol protocol) {
- if (protocol == null) {
- throw new IllegalArgumentException("protocol == null");
- }
- this.protocol = protocol;
- }
-
- private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
- Invoker<T> last = invoker;
- List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
-
- if (!filters.isEmpty()) {
- for (int i = filters.size() - 1; i >= 0; i--) {
- final Filter filter = filters.get(i);
- final Invoker<T> next = last;
- last = new Invoker<T>() {
-
- @Override
- public Class<T> getInterface() {
- return invoker.getInterface();
- }
-
- @Override
- public URL getUrl() {
- return invoker.getUrl();
- }
-
- @Override
- public boolean isAvailable() {
- return invoker.isAvailable();
- }
-
- @Override
- public Result invoke(Invocation invocation) throws RpcException {
- Result asyncResult;
- try {
- asyncResult = filter.invoke(next, invocation);
- } catch (Exception e) {
- if (filter instanceof ListenableFilter) {
- ListenableFilter listenableFilter = ((ListenableFilter) filter);
- try {
- Filter.Listener listener = listenableFilter.listener(invocation);
- if (listener != null) {
- listener.onError(e, invoker, invocation);
- }
- } finally {
- listenableFilter.removeListener(invocation);
- }
- } else if (filter instanceof Filter.Listener) {
- Filter.Listener listener = (Filter.Listener) filter;
- listener.onError(e, invoker, invocation);
- }
- throw e;
- } finally {
-
- }
- return asyncResult.whenCompleteWithContext((r, t) -> {
- if (filter instanceof ListenableFilter) {
- ListenableFilter listenableFilter = ((ListenableFilter) filter);
- Filter.Listener listener = listenableFilter.listener(invocation);
- try {
- if (listener != null) {
- if (t == null) {
- listener.onResponse(r, invoker, invocation);
- } else {
- listener.onError(t, invoker, invocation);
- }
- }
- } finally {
- listenableFilter.removeListener(invocation);
- }
- } else if (filter instanceof Filter.Listener) {
- Filter.Listener listener = (Filter.Listener) filter;
- if (t == null) {
- listener.onResponse(r, invoker, invocation);
- } else {
- listener.onError(t, invoker, invocation);
- }
- }
- });
- }
-
- @Override
- public void destroy() {
- invoker.destroy();
- }
-
- @Override
- public String toString() {
- return invoker.toString();
- }
- };
- }
- }
-
- return last;
- }
-
- @Override
- public int getDefaultPort() {
- return protocol.getDefaultPort();
- }
-
- @Override
- public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
- if (UrlUtils.isRegistry(invoker.getUrl())) {
- return protocol.export(invoker);
- }
- return protocol.export(buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER));
- }
-
- @Override
- public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
- if (UrlUtils.isRegistry(url)) {
- return protocol.refer(type, url);
- }
- return buildInvokerChain(protocol.refer(type, url), REFERENCE_FILTER_KEY, CommonConstants.CONSUMER);
- }
-
- @Override
- public void destroy() {
- protocol.destroy();
- }
-
- @Override
- public List<ProtocolServer> getServers() {
- return protocol.getServers();
- }
-
-}
+/*
+ * 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.rpc.support;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.rpc.Filter;
+import org.apache.dubbo.rpc.FilterChainBuilder;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.ListenableFilter;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+
+import java.util.List;
+
+public class DefaultFilterChainBuilder implements FilterChainBuilder {
+
+ @Override
+ public <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
+ Invoker<T> last = invoker;
+ List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
+
+ if (!filters.isEmpty()) {
+ for (int i = filters.size() - 1; i >= 0; i--) {
+ final Filter filter = filters.get(i);
+ final Invoker<T> next = last;
+ last = new Invoker<T>() {
+
+ @Override
+ public Class<T> getInterface() {
+ return invoker.getInterface();
+ }
+
+ @Override
+ public URL getUrl() {
+ return invoker.getUrl();
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return invoker.isAvailable();
+ }
+
+ @Override
+ public Result invoke(Invocation invocation) throws RpcException {
+ Result asyncResult;
+ try {
+ asyncResult = filter.invoke(next, invocation);
+ } catch (Exception e) {
+ if (filter instanceof ListenableFilter) {
+ ListenableFilter listenableFilter = ((ListenableFilter) filter);
+ try {
+ Filter.Listener listener = listenableFilter.listener(invocation);
+ if (listener != null) {
+ listener.onError(e, invoker, invocation);
+ }
+ } finally {
+ listenableFilter.removeListener(invocation);
+ }
+ } else if (filter instanceof Filter.Listener) {
+ Filter.Listener listener = (Filter.Listener) filter;
+ listener.onError(e, invoker, invocation);
+ }
+ throw e;
+ } finally {
+
+ }
+ return asyncResult.whenCompleteWithContext((r, t) -> {
+ if (filter instanceof ListenableFilter) {
+ ListenableFilter listenableFilter = ((ListenableFilter) filter);
+ Filter.Listener listener = listenableFilter.listener(invocation);
+ try {
+ if (listener != null) {
+ if (t == null) {
+ listener.onResponse(r, invoker, invocation);
+ } else {
+ listener.onError(t, invoker, invocation);
+ }
+ }
+ } finally {
+ listenableFilter.removeListener(invocation);
+ }
+ } else if (filter instanceof Filter.Listener) {
+ Filter.Listener listener = (Filter.Listener) filter;
+ if (t == null) {
+ listener.onResponse(r, invoker, invocation);
+ } else {
+ listener.onError(t, invoker, invocation);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void destroy() {
+ invoker.destroy();
+ }
+
+ @Override
+ public String toString() {
+ return invoker.toString();
+ }
+ };
+ }
+ }
+
+ return last;
+ }
+
+}
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.FilterChainBuilder b/dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.FilterChainBuilder
new file mode 100644
index 0000000..b3a9854
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.FilterChainBuilder
@@ -0,0 +1 @@
+default=org.apache.dubbo.rpc.support.DefaultFilterChainBuilder
\ No newline at end of file
diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/CallbackServiceCodec.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/CallbackServiceCodec.java
index 3b87068..607f291 100644
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/CallbackServiceCodec.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/CallbackServiceCodec.java
@@ -99,7 +99,7 @@ class CallbackServiceCodec {
params.put(IS_SERVER_KEY, Boolean.FALSE.toString());
// mark it's a callback, for troubleshooting
params.put(IS_CALLBACK_SERVICE, Boolean.TRUE.toString());
- String group = (url == null ? null : url.getParameter(GROUP_KEY));
+ String group = (url == null ? null : url.getGroup());
if (group != null && group.length() > 0) {
params.put(GROUP_KEY, group);
}
diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java
index 4fc52f7..d0e7f20 100644
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java
@@ -76,7 +76,7 @@ public class DubboInvoker<T> extends AbstractInvoker<T> {
super(serviceType, url, new String[]{INTERFACE_KEY, GROUP_KEY, TOKEN_KEY});
this.clients = clients;
// get version.
- this.version = url.getParameter(VERSION_KEY, "0.0.0");
+ this.version = url.getVersion("0.0.0");
this.invokers = invokers;
}
@@ -137,9 +137,7 @@ public class DubboInvoker<T> extends AbstractInvoker<T> {
// in order to avoid closing a client multiple times, a counter is used in case of connection per jvm, every
// time when client.close() is called, counter counts down once, and when counter reaches zero, client will be
// closed.
- if (super.isDestroyed()) {
- return;
- } else {
+ if (!super.isDestroyed()) {
// double check to avoid dup close
destroyLock.lock();
try {
diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java
index 791df67..0c9204a 100644
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java
@@ -197,9 +197,9 @@ public class DubboProtocol extends AbstractProtocol {
RpcInvocation invocation = new RpcInvocation(method, url.getParameter(INTERFACE_KEY), "", new Class<?>[0], new Object[0]);
invocation.setAttachment(PATH_KEY, url.getPath());
- invocation.setAttachment(GROUP_KEY, url.getParameter(GROUP_KEY));
+ invocation.setAttachment(GROUP_KEY, url.getGroup());
invocation.setAttachment(INTERFACE_KEY, url.getParameter(INTERFACE_KEY));
- invocation.setAttachment(VERSION_KEY, url.getParameter(VERSION_KEY));
+ invocation.setAttachment(VERSION_KEY, url.getVersion());
if (url.getParameter(STUB_EVENT_KEY, false)) {
invocation.setAttachment(STUB_EVENT_KEY, Boolean.TRUE.toString());
}