Merge branch '2.7.9-release'
# Conflicts:
# dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml
# dubbo-dependencies-bom/pom.xml
# dubbo-dependencies/dubbo-dependencies-zookeeper/pom.xml
# dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/InterfaceCompatibleRegistryProtocol.java
# dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/codec/ExchangeCodec.java
# dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/CodecSupport.java
# dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboCodec.java
# pom.xml
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..bb5d205
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,4 @@
+# Git will understand that all files specified are not text,
+# and it should not try to change them.
+# This will prevent file formatting (such as `crlf` endings to `lf` endings) while commit.
+* -text
\ No newline at end of file
diff --git a/Jenkinsfile b/Jenkinsfile
index 15eda40..83538c7 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -12,12 +12,12 @@
}
environment {
- JAVA_HOME = "${tool 'JDK 1.8 (latest)'}"
+ JAVA_HOME = "${tool 'jdk_1.8_latest'}"
}
tools {
- maven 'Maven 3 (latest)'
- jdk 'JDK 1.8 (latest)'
+ maven 'maven_3_latest'
+ jdk 'jdk_1.8_latest'
}
triggers {
diff --git a/README.md b/README.md
index 466ea7f..af561f9 100644
--- a/README.md
+++ b/README.md
@@ -33,16 +33,16 @@
```bash
# git clone https://github.com/apache/dubbo-samples.git
-# cd dubbo-samples/java/dubbo-samples-api
+# cd dubbo-samples/dubbo-samples-api
```
-There's a [README](https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-api/README.md) file under `dubbo-samples-api` directory. We recommend referencing the samples in that directory by following the below-mentioned instructions:
+There's a [README](https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-api/README.md) file under `dubbo-samples-api` directory. We recommend referencing the samples in that directory by following the below-mentioned instructions:
### Maven dependency
```xml
<properties>
- <dubbo.version>2.7.8</dubbo.version>
+ <dubbo.version>2.7.9</dubbo.version>
</properties>
<dependencies>
diff --git a/dubbo-all/pom.xml b/dubbo-all/pom.xml
index 050ae24..14a98e8 100644
--- a/dubbo-all/pom.xml
+++ b/dubbo-all/pom.xml
@@ -544,6 +544,13 @@
<scope>compile</scope>
<optional>true</optional>
</dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-metadata-report-failover</artifactId>
+ <version>${project.version}</version>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
<!-- Transitive dependencies -->
<dependency>
@@ -684,6 +691,7 @@
<include>org.apache.dubbo:dubbo-metadata-report-consul</include>
<include>org.apache.dubbo:dubbo-metadata-report-etcd</include>
<include>org.apache.dubbo:dubbo-metadata-report-nacos</include>
+ <include>org.apache.dubbo:dubbo-metadata-report-failover</include>
<include>org.apache.dubbo:dubbo-serialization-native-hession</include>
</includes>
</artifactSet>
@@ -859,6 +867,12 @@
META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory
</resource>
</transformer>
+ <transformer
+ implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+ <resource>
+ META-INF/dubbo/internal/org.apache.dubbo.metadata.store.failover.FailoverCondition
+ </resource>
+ </transformer>
<!-- @since 2.7.5 -->
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
diff --git a/dubbo-bom/pom.xml b/dubbo-bom/pom.xml
index a5b8b87..92aa370 100644
--- a/dubbo-bom/pom.xml
+++ b/dubbo-bom/pom.xml
@@ -250,6 +250,11 @@
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-registry-multiple</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>${project.version}</version>
</dependency>
@@ -399,6 +404,11 @@
<artifactId>dubbo-metadata-report-nacos</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-metadata-report-failover</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<!-- config-center -->
<dependency>
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 5d48264..208b0c2 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
@@ -53,4 +53,6 @@
boolean isDestroyed();
+ void discordAddresses();
+
}
\ No newline at end of file
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 1b1170a..95a540c 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
@@ -40,7 +40,6 @@
/**
* Abstract implementation of Directory: Invoker list returned from this Directory's list method have been filtered by Routers
- *
*/
public abstract class AbstractDirectory<T> implements Directory<T> {
@@ -59,10 +58,14 @@
protected RouterChain<T> routerChain;
public AbstractDirectory(URL url) {
- this(url, null);
+ this(url, null, false);
}
- public AbstractDirectory(URL url, RouterChain<T> routerChain) {
+ public AbstractDirectory(URL url, boolean isUrlFromRegistry) {
+ this(url, null, isUrlFromRegistry);
+ }
+
+ public AbstractDirectory(URL url, RouterChain<T> routerChain, boolean isUrlFromRegistry) {
if (url == null) {
throw new IllegalArgumentException("url == null");
}
@@ -72,8 +75,13 @@
this.consumedProtocol = this.queryMap.get(PROTOCOL_KEY) == null ? DUBBO : this.queryMap.get(PROTOCOL_KEY);
this.url = url.removeParameter(REFER_KEY).removeParameter(MONITOR_KEY);
- this.consumerUrl = this.url.setProtocol(consumedProtocol).setPath(path == null ? queryMap.get(INTERFACE_KEY) : path).addParameters(queryMap)
- .removeParameter(MONITOR_KEY);
+ URL consumerUrlFrom = this.url.setProtocol(consumedProtocol)
+ .setPath(path == null ? queryMap.get(INTERFACE_KEY) : path);
+ if (isUrlFromRegistry) {
+ // reserve parameters if url is already a consumer url
+ consumerUrlFrom = consumerUrlFrom.clearParameters();
+ }
+ this.consumerUrl = consumerUrlFrom.addParameters(queryMap).removeParameter(MONITOR_KEY);
setRouterChain(routerChain);
}
@@ -123,6 +131,11 @@
destroyed = true;
}
+ @Override
+ public void discordAddresses() {
+ // do nothing by default
+ }
+
protected abstract List<Invoker<T>> doList(Invocation invocation) throws RpcException;
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java
index 0595c63..db1b202 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java
@@ -49,7 +49,7 @@
}
public StaticDirectory(URL url, List<Invoker<T>> invokers, RouterChain<T> routerChain) {
- super(url == null && CollectionUtils.isNotEmpty(invokers) ? invokers.get(0).getUrl() : url, routerChain);
+ super(url == null && CollectionUtils.isNotEmpty(invokers) ? invokers.get(0).getUrl() : url, routerChain, false);
if (CollectionUtils.isEmpty(invokers)) {
throw new IllegalArgumentException("invokers == null");
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java
index 77429b5..91a0f8e 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java
@@ -34,7 +34,6 @@
import org.apache.dubbo.rpc.cluster.router.tag.model.TagRouterRule;
import org.apache.dubbo.rpc.cluster.router.tag.model.TagRuleParser;
-import java.net.UnknownHostException;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -227,8 +226,6 @@
if ((ANYHOST_VALUE + ":" + port).equals(address)) {
return true;
}
- } catch (UnknownHostException e) {
- logger.error("The format of ip address is invalid in tag route. Address :" + address, e);
} catch (Exception e) {
logger.error("The format of ip address is invalid in tag route. Address :" + address, e);
}
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..fcfb132 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
@@ -16,6 +16,7 @@
*/
package org.apache.dubbo.rpc.cluster.support;
+import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.rpc.Invocation;
@@ -30,11 +31,13 @@
/**
* BroadcastClusterInvoker
- *
*/
public class BroadcastClusterInvoker<T> extends AbstractClusterInvoker<T> {
private static final Logger logger = LoggerFactory.getLogger(BroadcastClusterInvoker.class);
+ private static final String BROADCAST_FAIL_PERCENT_KEY = "broadcast.fail.percent";
+ private static final int MAX_BROADCAST_FAIL_PERCENT = 100;
+ private static final int MIN_BROADCAST_FAIL_PERCENT = 0;
public BroadcastClusterInvoker(Directory<T> directory) {
super(directory);
@@ -47,21 +50,67 @@
RpcContext.getContext().setInvokers((List) invokers);
RpcException exception = null;
Result result = null;
+ URL url = getUrl();
+ // The value range of broadcast.fail.threshold must be 0~100.
+ // 100 means that an exception will be thrown last, and 0 means that as long as an exception occurs, it will be thrown.
+ // see https://github.com/apache/dubbo/pull/7174
+ int broadcastFailPercent = url.getParameter(BROADCAST_FAIL_PERCENT_KEY, MAX_BROADCAST_FAIL_PERCENT);
+
+ if (broadcastFailPercent < MIN_BROADCAST_FAIL_PERCENT || broadcastFailPercent > MAX_BROADCAST_FAIL_PERCENT) {
+ logger.info(String.format("The value corresponding to the broadcast.fail.percent parameter must be between 0 and 100. " +
+ "The current setting is %s, which is reset to 100.", broadcastFailPercent));
+ broadcastFailPercent = MAX_BROADCAST_FAIL_PERCENT;
+ }
+
+ int failThresholdIndex = invokers.size() * broadcastFailPercent / MAX_BROADCAST_FAIL_PERCENT;
+ int failIndex = 0;
for (Invoker<T> invoker : invokers) {
try {
result = invoker.invoke(invocation);
- } catch (RpcException e) {
- exception = e;
- logger.warn(e.getMessage(), e);
+ if (null != result && result.hasException()) {
+ Throwable resultException = result.getException();
+ if (null != resultException) {
+ exception = getRpcException(result.getException());
+ logger.warn(exception.getMessage(), exception);
+ if (failIndex == failThresholdIndex) {
+ break;
+ } else {
+ failIndex++;
+ }
+ }
+ }
} catch (Throwable e) {
- exception = new RpcException(e.getMessage(), e);
- logger.warn(e.getMessage(), e);
+ exception = getRpcException(e);
+ logger.warn(exception.getMessage(), exception);
+ if (failIndex == failThresholdIndex) {
+ break;
+ } else {
+ failIndex++;
+ }
}
}
+
if (exception != null) {
+ if (failIndex == failThresholdIndex) {
+ logger.debug(
+ String.format("The number of BroadcastCluster call failures has reached the threshold %s", failThresholdIndex));
+ } else {
+ logger.debug(String.format("The number of BroadcastCluster call failures has not reached the threshold %s, fail size is %s",
+ failIndex));
+ }
throw exception;
}
+
return result;
}
+ private RpcException getRpcException(Throwable throwable) {
+ RpcException rpcException = null;
+ if (throwable instanceof RpcException) {
+ rpcException = (RpcException) throwable;
+ } else {
+ rpcException = new RpcException(throwable.getMessage(), throwable);
+ }
+ return rpcException;
+ }
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationClusterComparator.java
similarity index 70%
copy from dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java
copy to dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationClusterComparator.java
index 2042277..72dfdcf 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationClusterComparator.java
@@ -14,7 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.common;
+package org.apache.dubbo.rpc.cluster.support.migration;
-public class ConfigurationURL extends URL {
-}
+import org.apache.dubbo.common.extension.SPI;
+import org.apache.dubbo.rpc.Invoker;
+
+import java.util.List;
+
+@SPI
+public interface MigrationClusterComparator {
+
+ <T> boolean shouldMigrate(List<Invoker<T>> interfaceInvokers, List<Invoker<T>> serviceInvokers);
+}
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationClusterInvoker.java
new file mode 100644
index 0000000..e15fa11
--- /dev/null
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationClusterInvoker.java
@@ -0,0 +1,54 @@
+/*
+ * 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.migration;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.cluster.ClusterInvoker;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public interface MigrationClusterInvoker<T> extends ClusterInvoker<T> {
+
+ boolean isServiceInvoker();
+
+ MigrationRule getMigrationRule();
+
+ void setMigrationRule(MigrationRule rule);
+
+ void destroyServiceDiscoveryInvoker(ClusterInvoker<?> invoker);
+
+ void discardServiceDiscoveryInvokerAddress(ClusterInvoker<?> invoker);
+
+ void discardInterfaceInvokerAddress(ClusterInvoker<T> invoker);
+
+ void refreshServiceDiscoveryInvoker();
+
+ void refreshInterfaceInvoker();
+
+ void destroyInterfaceInvoker(ClusterInvoker<T> invoker);
+
+ boolean isMigrationMultiRegsitry();
+
+ void migrateToServiceDiscoveryInvoker(boolean forceMigrate);
+
+ void reRefer(URL newSubscribeUrl);
+
+ void fallbackToInterfaceInvoker();
+
+ AtomicBoolean invokersChanged();
+
+}
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationRule.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationRule.java
new file mode 100644
index 0000000..7b6cb64
--- /dev/null
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationRule.java
@@ -0,0 +1,90 @@
+/*
+ * 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.migration;
+
+import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+import java.util.Optional;
+
+public class MigrationRule {
+ private static final String DUBBO_SERVICEDISCOVERY_MIGRATION_KEY = "dubbo.application.service-discovery.migration";
+ public static final String DUBBO_SERVICEDISCOVERY_MIGRATION_GROUP = "MIGRATION";
+ public static final String RULE_KEY = ApplicationModel.getName() + ".migration";
+
+ private static DynamicConfiguration configuration = null;
+
+ static {
+ Optional<DynamicConfiguration> optional = ApplicationModel.getEnvironment().getDynamicConfiguration();
+ if (optional.isPresent()) {
+ configuration = optional.get();
+ }
+ }
+
+ private String key;
+ private MigrationStep step = MigrationStep.FORCE_INTERFACE;
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public MigrationStep getStep() {
+ return step;
+ }
+
+ public void setStep(MigrationStep step) {
+ this.step = step;
+ }
+
+ public static MigrationRule parse(String rawRule) {
+ if (null == configuration) {
+ return getMigrationRule(null);
+ }
+
+ if (StringUtils.isBlank(rawRule) || "INIT".equals(rawRule)) {
+ String step = (String)configuration.getInternalProperty(DUBBO_SERVICEDISCOVERY_MIGRATION_KEY);
+ return getMigrationRule(step);
+
+ }
+
+ Constructor constructor = new Constructor(MigrationRule.class);
+ Yaml yaml = new Yaml(constructor);
+ return yaml.load(rawRule);
+ }
+
+ public static MigrationRule queryRule() {
+ if (null == configuration) {
+ return getMigrationRule(null);
+ }
+
+ String rawRule = configuration.getConfig(MigrationRule.RULE_KEY, DUBBO_SERVICEDISCOVERY_MIGRATION_GROUP);
+ return parse(rawRule);
+ }
+
+ private static MigrationRule getMigrationRule(String step) {
+ MigrationRule rule = new MigrationRule();
+ rule.setStep(Enum.valueOf(MigrationStep.class, StringUtils.isBlank(step) ? MigrationStep.APPLICATION_FIRST.name() : step));
+ return rule;
+ }
+}
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationStep.java
similarity index 83%
copy from dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java
copy to dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationStep.java
index 2042277..653e6c5 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationStep.java
@@ -14,7 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.common;
+package org.apache.dubbo.rpc.cluster.support.migration;
-public class ConfigurationURL extends URL {
-}
+public enum MigrationStep {
+ FORCE_INTERFACE,
+ APPLICATION_FIRST,
+ FORCE_APPLICATION
+}
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareClusterInvoker.java
index 97b7a0b..48215e9 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareClusterInvoker.java
@@ -16,6 +16,7 @@
*/
package org.apache.dubbo.rpc.cluster.support.registry;
+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.utils.StringUtils;
@@ -27,12 +28,20 @@
import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.LoadBalance;
import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;
+import org.apache.dubbo.rpc.cluster.support.migration.MigrationClusterInvoker;
+import org.apache.dubbo.rpc.cluster.support.migration.MigrationClusterComparator;
+import org.apache.dubbo.rpc.cluster.support.migration.MigrationRule;
+import org.apache.dubbo.rpc.cluster.support.migration.MigrationStep;
import org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.CommonConstants.PREFERRED_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.LOADBALANCE_AMONG_REGISTRIES;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_ZONE;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_ZONE_FORCE;
import static org.apache.dubbo.common.constants.RegistryConstants.ZONE_KEY;
@@ -50,6 +59,8 @@
private static final Logger logger = LoggerFactory.getLogger(ZoneAwareClusterInvoker.class);
+ private final LoadBalance loadBalanceAmongRegistries = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(LOADBALANCE_AMONG_REGISTRIES);
+
public ZoneAwareClusterInvoker(Directory<T> directory) {
super(directory);
}
@@ -61,7 +72,7 @@
for (Invoker<T> invoker : invokers) {
ClusterInvoker<T> clusterInvoker = (ClusterInvoker<T>) invoker;
if (clusterInvoker.isAvailable() && clusterInvoker.getRegistryUrl()
- .getParameter(PREFERRED_KEY, false)) {
+ .getParameter(REGISTRY_KEY + "." + PREFERRED_KEY, false)) {
return clusterInvoker.invoke(invocation);
}
}
@@ -71,7 +82,7 @@
if (StringUtils.isNotEmpty(zone)) {
for (Invoker<T> invoker : invokers) {
ClusterInvoker<T> clusterInvoker = (ClusterInvoker<T>) invoker;
- if (clusterInvoker.isAvailable() && zone.equals(clusterInvoker.getRegistryUrl().getParameter(ZONE_KEY))) {
+ if (clusterInvoker.isAvailable() && zone.equals(clusterInvoker.getRegistryUrl().getParameter(REGISTRY_KEY + "." + ZONE_KEY))) {
return clusterInvoker.invoke(invocation);
}
}
@@ -85,7 +96,7 @@
// load balance among all registries, with registry weight count in.
- Invoker<T> balancedInvoker = select(loadbalance, invocation, invokers, null);
+ Invoker<T> balancedInvoker = select(loadBalanceAmongRegistries, invocation, invokers, null);
if (balancedInvoker.isAvailable()) {
return balancedInvoker.invoke(invocation);
}
@@ -102,4 +113,155 @@
return invokers.get(0).invoke(invocation);
}
+ @Override
+ protected List<Invoker<T>> list(Invocation invocation) throws RpcException {
+ List<Invoker<T>> invokers = super.list(invocation);
+
+ if (null == invokers || invokers.size() < 2) {
+ return invokers;
+ }
+
+ // 开关
+ //
+
+ //List<Invoker<T>> interfaceInvokers = invokers.stream().filter( s -> !((MigrationCluserInvoker)s).isServiceInvoker()).collect(Collectors.toList());
+ //List<Invoker<T>> serviceInvokers = invokers.stream().filter( s -> ((MigrationCluserInvoker)s).isServiceInvoker()).collect(Collectors.toList());
+
+ List<Invoker<T>> interfaceInvokers = new ArrayList<>();
+ List<Invoker<T>> serviceInvokers = new ArrayList<>();
+ boolean addreddChanged = false;
+ for (Invoker<T> invoker : invokers) {
+ MigrationClusterInvoker migrationClusterInvoker = (MigrationClusterInvoker) invoker;
+ if (migrationClusterInvoker.isServiceInvoker()) {
+ serviceInvokers.add(invoker);
+ } else {
+ interfaceInvokers.add(invoker);
+ }
+
+ if (migrationClusterInvoker.invokersChanged().compareAndSet(true, false)) {
+ addreddChanged = true;
+ }
+ }
+
+ if (serviceInvokers.isEmpty() || interfaceInvokers.isEmpty()) {
+ return invokers;
+ }
+
+ MigrationRule rule = null;
+
+ for (Invoker<T> invoker : serviceInvokers) {
+ MigrationClusterInvoker migrationClusterInvoker = (MigrationClusterInvoker) invoker;
+ if (null == rule) {
+ rule = migrationClusterInvoker.getMigrationRule();
+ } else {
+ // 不一致
+ if (!rule.equals(migrationClusterInvoker.getMigrationRule())) {
+ rule = MigrationRule.queryRule();
+ break;
+ }
+ }
+ }
+
+ MigrationStep step = rule.getStep();
+
+ switch (step) {
+ case FORCE_INTERFACE:
+ clusterRefresh(addreddChanged, interfaceInvokers);
+ clusterDestory(addreddChanged, serviceInvokers, true);
+ if (logger.isDebugEnabled()) {
+ logger.debug("step is FORCE_INTERFACE");
+ }
+ return interfaceInvokers;
+
+ case APPLICATION_FIRST:
+ clusterRefresh(addreddChanged, serviceInvokers);
+ clusterRefresh(addreddChanged, interfaceInvokers);
+
+ if (serviceInvokers.size() > 0) {
+ if (shouldMigrate(addreddChanged, serviceInvokers, interfaceInvokers)) {
+ //clusterDestory(addreddChanged, interfaceInvokers, false);
+ if (logger.isDebugEnabled()) {
+ logger.debug("step is APPLICATION_FIRST shouldMigrate true get serviceInvokers");
+ }
+ return serviceInvokers;
+
+ } else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("step is APPLICATION_FIRST shouldMigrate false get interfaceInvokers");
+ }
+ return interfaceInvokers;
+ }
+ } else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("step is APPLICATION_FIRST serviceInvokers is empty get interfaceInvokers");
+ }
+ return interfaceInvokers;
+ }
+
+
+ case FORCE_APPLICATION:
+ clusterRefresh(addreddChanged, serviceInvokers);
+ clusterDestory(addreddChanged, interfaceInvokers, true);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("step is FORCE_APPLICATION");
+ }
+
+ return serviceInvokers;
+ }
+
+ throw new UnsupportedOperationException(rule.getStep().name());
+ }
+
+
+ private boolean shouldMigrate(boolean addressChanged, List<Invoker<T>> serviceInvokers, List<Invoker<T>> interfaceInvokers) {
+ Set<MigrationClusterComparator> detectors = ExtensionLoader.getExtensionLoader(MigrationClusterComparator.class).getSupportedExtensionInstances();
+ if (null != detectors && detectors.size() > 0) {
+ if (detectors.stream().allMatch(s -> s.shouldMigrate(interfaceInvokers, serviceInvokers))) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ List<Invoker<T>> availableServiceInvokers = serviceInvokers.stream().filter( s -> ((MigrationClusterInvoker)s).isAvailable()).collect(Collectors.toList());
+ if (availableServiceInvokers.isEmpty()) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ private void clusterDestory(boolean addressChanged, List<Invoker<T>> invokers, boolean destroySub) {
+ if (addressChanged) {
+ invokers.forEach(s -> {
+ MigrationClusterInvoker invoker = (MigrationClusterInvoker)s;
+ if (invoker.isServiceInvoker()) {
+ invoker.discardServiceDiscoveryInvokerAddress(invoker);
+ if (destroySub) {
+ invoker.destroyServiceDiscoveryInvoker(invoker);
+ }
+ } else {
+ invoker.discardInterfaceInvokerAddress(invoker);
+ if (destroySub) {
+ invoker.destroyInterfaceInvoker(invoker);
+ }
+ }
+ });
+ }
+ }
+
+ private void clusterRefresh(boolean addressChanged, List<Invoker<T>> invokers) {
+ if (addressChanged) {
+ invokers.forEach( s -> {
+ MigrationClusterInvoker invoker = (MigrationClusterInvoker)s;
+ if (invoker.isServiceInvoker()) {
+ invoker.refreshServiceDiscoveryInvoker();
+ } else {
+ invoker.refreshInterfaceInvoker();
+ }
+ });
+ }
+ }
+
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvoker.java
index a682297..51d0a49 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvoker.java
@@ -162,7 +162,7 @@
/**
* Return MockInvoker
* Contract:
- * directory.list() will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is present in invocation, otherwise, a list of mock invokers will return.
+ * directory.list() will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is absent or not true in invocation, otherwise, a list of mock invokers will return.
* if directory.list() returns more than one mock invoker, only one of them will be used.
*
* @param invocation
@@ -174,7 +174,7 @@
if (invocation instanceof RpcInvocation) {
//Note the implicit contract (although the description is added to the interface declaration, but extensibility is a problem. The practice placed in the attachment needs to be improved)
((RpcInvocation) invocation).setAttachment(INVOCATION_NEED_MOCK, Boolean.TRUE.toString());
- //directory will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is present in invocation, otherwise, a list of mock invokers will return.
+ //directory will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is absent or not true in invocation, otherwise, a list of mock invokers will return.
try {
invokers = directory.list(invocation);
} catch (RpcException e) {
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalanceTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalanceTest.java
index 8d77aa4..bb6260c 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalanceTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalanceTest.java
@@ -131,13 +131,7 @@
recycleTimeField = RoundRobinLoadBalance.class.getDeclaredField("RECYCLE_PERIOD");
recycleTimeField.setAccessible(true);
recycleTimeField.setInt(RoundRobinLoadBalance.class, 10);
- } catch (NoSuchFieldException e) {
- Assertions.assertTrue(true, "getField failed");
- } catch (SecurityException e) {
- Assertions.assertTrue(true, "getField failed");
- } catch (IllegalArgumentException e) {
- Assertions.assertTrue(true, "getField failed");
- } catch (IllegalAccessException e) {
+ } catch (NoSuchFieldException | IllegalAccessException | IllegalArgumentException | SecurityException e) {
Assertions.assertTrue(true, "getField failed");
}
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationRuleTest.java
similarity index 78%
copy from dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java
copy to dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationRuleTest.java
index 2042277..5bd431d 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/migration/MigrationRuleTest.java
@@ -14,7 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.common;
+package org.apache.dubbo.rpc.cluster.support.migration;
-public class ConfigurationURL extends URL {
-}
+import org.junit.jupiter.api.Test;
+
+public class MigrationRuleTest {
+
+ @Test
+ public void testParse() {
+ System.out.println("xxx");
+ }
+
+}
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Parameters.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Parameters.java
index 90e3415..790c476 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/Parameters.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Parameters.java
@@ -244,6 +244,9 @@
@Override
public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
return parameters.equals(o);
}
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 873f461..86e7a02 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
@@ -246,6 +246,11 @@
int port = 0;
String path = null;
Map<String, String> parameters = null;
+ // ignore the url content following '#'
+ int poundIndex = url.indexOf('#');
+ if (poundIndex != -1) {
+ url = url.substring(0, poundIndex);
+ }
int i = url.indexOf('?'); // separator between body and parameters
if (i >= 0) {
String[] parts = url.substring(i + 1).split("&");
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 2699e48..06db68e 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
@@ -20,6 +20,7 @@
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;
@@ -226,11 +227,29 @@
if (isEncoded) {
String name = decodeComponent(str, nameStart, valueStart - 3, false, tempBuf);
String value = decodeComponent(str, valueStart, valueEnd, false, tempBuf);
+ if (valueStart == valueEnd) {
+ value = name;
+ } else {
+ value = decodeComponent(str, valueStart, valueEnd, false, tempBuf);
+ }
params.put(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 name = str.substring(nameStart, valueStart - 1);
String value = str.substring(valueStart, valueEnd);
+ if (valueStart == valueEnd) {
+ value = name;
+ } else {
+ value = str.substring(valueStart, valueEnd);
+ }
params.put(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/bytecode/ClassGenerator.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java
index b81b7a3..252c3aa 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java
@@ -340,9 +340,7 @@
return mCtc.toClass(loader, pd);
} catch (RuntimeException e) {
throw e;
- } catch (NotFoundException e) {
- throw new RuntimeException(e.getMessage(), e);
- } catch (CannotCompileException e) {
+ } catch (NotFoundException | CannotCompileException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/CustomizedLoaderClassPath.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/CustomizedLoaderClassPath.java
index b1ef491..918f2b1 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/CustomizedLoaderClassPath.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/CustomizedLoaderClassPath.java
@@ -49,8 +49,9 @@
public String toString() {
Object cl = null;
- if (clref != null)
+ if (clref != null) {
cl = clref.get();
+ }
return cl == null ? "<null>" : cl.toString();
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java
index 365cb7f..0406dfb 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java
@@ -49,9 +49,7 @@
public static Object newInstance(String name) {
try {
return forName(name).newInstance();
- } catch (InstantiationException e) {
- throw new IllegalStateException(e.getMessage(), e);
- } catch (IllegalAccessException e) {
+ } catch (InstantiationException | IllegalAccessException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/CompositeConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/CompositeConfiguration.java
index eebf5a0..29c624b 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/CompositeConfiguration.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/CompositeConfiguration.java
@@ -38,6 +38,9 @@
*/
private List<Configuration> configList = new LinkedList<Configuration>();
+ //FIXME, consider change configList to SortedMap to replace this boolean status.
+ private boolean dynamicIncluded;
+
public CompositeConfiguration() {
this(null, null);
}
@@ -58,6 +61,15 @@
}
}
+ public void setDynamicIncluded(boolean dynamicIncluded) {
+ this.dynamicIncluded = dynamicIncluded;
+ }
+
+ //FIXME, consider change configList to SortedMap to replace this boolean status.
+ public boolean isDynamicIncluded() {
+ return dynamicIncluded;
+ }
+
public void addConfiguration(Configuration configuration) {
if (configList.contains(configuration)) {
return;
@@ -113,4 +125,4 @@
}
return value != null ? value : defaultValue;
}
-}
+}
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java
index a7c0693..ed79f15 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java
@@ -66,6 +66,10 @@
return ApplicationModel.getEnvironment().getConfiguration();
}
+ public static Configuration getDynamicGlobalConfiguration() {
+ return ApplicationModel.getEnvironment().getDynamicGlobalConfiguration();
+ }
+
// FIXME
@SuppressWarnings("deprecation")
public static int getServerShutdownTimeout() {
@@ -92,6 +96,14 @@
return timeout;
}
+ public static String getDynamicProperty(String property) {
+ return getDynamicProperty(property, null);
+ }
+
+ public static String getDynamicProperty(String property, String defaultValue) {
+ return StringUtils.trim(getDynamicGlobalConfiguration().getString(property, defaultValue));
+ }
+
public static String getProperty(String property) {
return getProperty(property, null);
}
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 b5f24f7..cfc1b01 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.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,7 @@
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;
@@ -41,6 +44,8 @@
private final InmemoryConfiguration appExternalConfiguration;
private CompositeConfiguration globalConfiguration;
+ private CompositeConfiguration dynamicGlobalConfiguration;
+
private Map<String, String> externalConfigurationMap = new HashMap<>();
private Map<String, String> appExternalConfigurationMap = new HashMap<>();
@@ -146,9 +151,6 @@
public Configuration getConfiguration() {
if (globalConfiguration == null) {
globalConfiguration = new CompositeConfiguration();
- if (dynamicConfiguration != null) {
- globalConfiguration.addConfiguration(dynamicConfiguration);
- }
globalConfiguration.addConfiguration(systemConfiguration);
globalConfiguration.addConfiguration(environmentConfiguration);
globalConfiguration.addConfiguration(appExternalConfiguration);
@@ -158,6 +160,21 @@
return globalConfiguration;
}
+ public Configuration getDynamicGlobalConfiguration() {
+ if (dynamicGlobalConfiguration == null) {
+ if (dynamicConfiguration == null) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("dynamicConfiguration is null , return globalConfiguration.");
+ }
+ return globalConfiguration;
+ }
+ dynamicGlobalConfiguration = new CompositeConfiguration();
+ dynamicGlobalConfiguration.addConfiguration(dynamicConfiguration);
+ dynamicGlobalConfiguration.addConfiguration(getConfiguration());
+ }
+ return dynamicGlobalConfiguration;
+ }
+
public boolean isConfigCenterFirst() {
return configCenterFirst;
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangedEvent.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangedEvent.java
index 8195558..f7c2ec7 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangedEvent.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangedEvent.java
@@ -74,8 +74,12 @@
@Override
public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof ConfigChangedEvent)) return false;
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof ConfigChangedEvent)) {
+ return false;
+ }
ConfigChangedEvent that = (ConfigChangedEvent) o;
return Objects.equals(getKey(), that.getKey()) &&
Objects.equals(getGroup(), that.getGroup()) &&
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 3feeeb2..4fa5595 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
@@ -59,10 +59,9 @@
String COMPATIBLE_CONFIG_KEY = "compatible_config";
- String REGISTRY_DUPLICATE_KEY = "duplicate";
+ String REGISTRY_PUBLISH_INTERFACE_KEY = "publish-interface";
- String ENABLE_REGISTRY_DIRECTORY_AUTO_MIGRATION = "enable-auto-migration";
-
+ String DUBBO_PUBLISH_INTERFACE_DEFAULT_KEY = "dubbo.application.publish-interface";
/**
* The parameter key of Dubbo Registry type
*
@@ -114,4 +113,10 @@
String ZONE_KEY = "zone";
String REGISTRY_SERVICE_REFERENCE_PATH = "org.apache.dubbo.registry.RegistryService";
+
+ String INIT = "INIT";
+
+ boolean MIGRATION_MULTI_REGSITRY = false;
+
+ String LOADBALANCE_AMONG_REGISTRIES = "random";
}
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..dc65572 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
@@ -599,26 +599,25 @@
}
private IllegalStateException findException(String name) {
- for (Map.Entry<String, IllegalStateException> entry : exceptions.entrySet()) {
- if (entry.getKey().toLowerCase().contains(name.toLowerCase())) {
- return entry.getValue();
- }
- }
StringBuilder buf = new StringBuilder("No such extension " + type.getName() + " by name " + name);
-
int i = 1;
for (Map.Entry<String, IllegalStateException> entry : exceptions.entrySet()) {
- if (i == 1) {
- buf.append(", possible causes: ");
+ if (entry.getKey().toLowerCase().startsWith(name.toLowerCase())) {
+ if (i == 1) {
+ buf.append(", possible causes: ");
+ }
+ buf.append("\r\n(");
+ buf.append(i++);
+ buf.append(") ");
+ buf.append(entry.getKey());
+ buf.append(":\r\n");
+ buf.append(StringUtils.toString(entry.getValue()));
}
+ }
- buf.append("\r\n(");
- buf.append(i++);
- buf.append(") ");
- buf.append(entry.getKey());
- buf.append(":\r\n");
- buf.append(StringUtils.toString(entry.getValue()));
+ if (i == 1) {
+ buf.append(", no related exception was found, please check whether related SPI module is missing.");
}
return new IllegalStateException(buf.toString());
}
@@ -847,6 +846,7 @@
try {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
String line;
+ String clazz = null;
while ((line = reader.readLine()) != null) {
final int ci = line.indexOf('#');
if (ci >= 0) {
@@ -859,10 +859,12 @@
int i = line.indexOf('=');
if (i > 0) {
name = line.substring(0, i).trim();
- line = line.substring(i + 1).trim();
+ clazz = line.substring(i + 1).trim();
+ } else {
+ clazz = line;
}
- if (line.length() > 0 && !isExcluded(line, excludedPackages)) {
- loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name, overridden);
+ if (StringUtils.isNotEmpty(clazz) && !isExcluded(clazz, excludedPackages)) {
+ loadClass(extensionClasses, resourceURL, Class.forName(clazz, true, classLoader), name, overridden);
}
} catch (Throwable t) {
IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/json/J2oVisitor.java b/dubbo-common/src/main/java/org/apache/dubbo/common/json/J2oVisitor.java
index 3aa3fd9..bc6e4e3 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/json/J2oVisitor.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/json/J2oVisitor.java
@@ -259,9 +259,7 @@
try {
mValue = mType.newInstance();
mWrapper = Wrapper.getWrapper(mType);
- } catch (IllegalAccessException e) {
- throw new ParseException(StringUtils.toString(e));
- } catch (InstantiationException e) {
+ } catch (IllegalAccessException | InstantiationException e) {
throw new ParseException(StringUtils.toString(e));
}
}
@@ -304,9 +302,7 @@
field.setAccessible(true);
}
field.set(mValue, obj);
- } catch (NoSuchFieldException e) {
- throw new ParseException(StringUtils.toString(e));
- } catch (IllegalAccessException e) {
+ } catch (NoSuchFieldException | IllegalAccessException e) {
throw new ParseException(StringUtils.toString(e));
}
} else if (!CLASS_PROPERTY.equals(name)) {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/lang/Prioritized.java b/dubbo-common/src/main/java/org/apache/dubbo/common/lang/Prioritized.java
index babb3ed..76a6a0b 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/lang/Prioritized.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/lang/Prioritized.java
@@ -63,7 +63,7 @@
/**
* Get the priority
*
- * @return the default is {@link #MIN_PRIORITY minimum one}
+ * @return the default is {@link #NORMAL_PRIORITY}
*/
default int getPriority() {
return NORMAL_PRIORITY;
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalRunnable.java b/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalRunnable.java
new file mode 100644
index 0000000..6cc8db8
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalRunnable.java
@@ -0,0 +1,53 @@
+/*
+ * 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.threadlocal;
+
+
+/**
+ * InternalRunnable
+ * There is a risk of memory leak when using {@link InternalThreadLocal} without calling
+ * {@link InternalThreadLocal#removeAll()}.
+ * This design is learning from {@see io.netty.util.concurrent.FastThreadLocalRunnable} which is in Netty.
+ */
+public class InternalRunnable implements Runnable{
+ private final Runnable runnable;
+
+ public InternalRunnable(Runnable runnable){
+ this.runnable=runnable;
+ }
+
+ /**
+ * After the task execution is completed, it will call {@link InternalThreadLocal#removeAll()} to clear
+ * unnecessary variables in the thread.
+ */
+ @Override
+ public void run() {
+ try{
+ runnable.run();
+ }finally {
+ InternalThreadLocal.removeAll();
+ }
+ }
+
+ /**
+ * Wrap ordinary Runnable into {@link InternalThreadLocal}.
+ */
+ static Runnable Wrap(Runnable runnable){
+ return runnable instanceof InternalRunnable?runnable:new InternalRunnable(runnable);
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/NamedInternalThreadFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/NamedInternalThreadFactory.java
index 52b8d56..0bb305f 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/NamedInternalThreadFactory.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/NamedInternalThreadFactory.java
@@ -40,7 +40,7 @@
@Override
public Thread newThread(Runnable runnable) {
String name = mPrefix + mThreadNum.getAndIncrement();
- InternalThread ret = new InternalThread(mGroup, runnable, name, 0);
+ InternalThread ret = new InternalThread(mGroup, InternalRunnable.Wrap(runnable), name, 0);
ret.setDaemon(mDaemon);
return ret;
}
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 1669089..4325ffa 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
@@ -21,6 +21,7 @@
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.threadpool.ThreadPool;
+import org.apache.dubbo.common.utils.ExecutorUtil;
import org.apache.dubbo.common.utils.NamedThreadFactory;
import java.util.Map;
@@ -71,12 +72,9 @@
* @return
*/
public synchronized ExecutorService createExecutorIfAbsent(URL url) {
- String componentKey = EXECUTOR_SERVICE_COMPONENT_KEY;
- if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {
- componentKey = CONSUMER_SIDE;
- }
- Map<Integer, ExecutorService> executors = data.computeIfAbsent(componentKey, k -> new ConcurrentHashMap<>());
- Integer portKey = url.getPort();
+ Map<Integer, ExecutorService> executors = data.computeIfAbsent(EXECUTOR_SERVICE_COMPONENT_KEY, k -> new ConcurrentHashMap<>());
+ //issue-7054:Consumer's executor is sharing globally, key=Integer.MAX_VALUE. Provider's executor is sharing by protocol.
+ Integer portKey = CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY)) ? Integer.MAX_VALUE : url.getPort();
ExecutorService executor = executors.computeIfAbsent(portKey, k -> createExecutor(url));
// If executor has been shut down, create a new one
if (executor.isShutdown() || executor.isTerminated()) {
@@ -88,12 +86,7 @@
}
public ExecutorService getExecutor(URL url) {
- String componentKey = EXECUTOR_SERVICE_COMPONENT_KEY;
- if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {
- componentKey = CONSUMER_SIDE;
- }
- Map<Integer, ExecutorService> executors = data.get(componentKey);
-
+ Map<Integer, ExecutorService> executors = data.get(EXECUTOR_SERVICE_COMPONENT_KEY);
/**
* It's guaranteed that this method is called after {@link #createExecutorIfAbsent(URL)}, so data should already
* have Executor instances generated and stored.
@@ -103,17 +96,20 @@
"before coming to here.");
return null;
}
-
- Integer portKey = url.getPort();
+ //issue-7054:Consumer's executor is sharing globally, key=Integer.MAX_VALUE. Provider's executor is sharing by protocol.
+ Integer portKey = CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY)) ? Integer.MAX_VALUE : url.getPort();
ExecutorService executor = executors.get(portKey);
- if (executor != null) {
- if (executor.isShutdown() || executor.isTerminated()) {
- executors.remove(portKey);
- executor = createExecutor(url);
- executors.put(portKey, executor);
- }
+ if (executor != null && (executor.isShutdown() || executor.isTerminated())) {
+ executors.remove(portKey);
+ // Does not re-create a shutdown executor, use SHARED_EXECUTOR for downgrade.
+ executor = null;
+ logger.info("Executor for " + url + " is shutdown.");
}
- return executor;
+ if (executor == null) {
+ return SHARED_EXECUTOR;
+ } else {
+ return executor;
+ }
}
@Override
@@ -159,6 +155,19 @@
return SHARED_EXECUTOR;
}
+ @Override
+ public void destroyAll() {
+ data.values().forEach(executors -> {
+ if (executors != null) {
+ executors.values().forEach(executor -> {
+ if (executor != null && !executor.isShutdown()) {
+ ExecutorUtil.shutdownNow(executor, 100);
+ }
+ });
+ }
+ });
+ }
+
private ExecutorService createExecutor(URL url) {
return (ExecutorService) ExtensionLoader.getExtensionLoader(ThreadPool.class).getAdaptiveExtension().getExecutor(url);
}
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 af3b110..b19fcdf 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
@@ -64,4 +64,8 @@
*/
ExecutorService getSharedExecutor();
+ /**
+ * Destroy all executors that are not in shutdown state
+ */
+ void destroyAll();
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReport.java b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReport.java
index c6865eb..6347e14 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReport.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReport.java
@@ -31,8 +31,10 @@
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.threadpool.event.ThreadPoolExhaustedEvent;
import org.apache.dubbo.common.utils.JVMUtil;
+import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.event.EventDispatcher;
+import static java.lang.String.format;
import static org.apache.dubbo.common.constants.CommonConstants.DUMP_DIRECTORY;
/**
@@ -61,6 +63,8 @@
private static Semaphore guard = new Semaphore(1);
+ private static final String USER_HOME = System.getProperty("user.home");
+
public AbortPolicyWithReport(String threadName, URL url) {
this.threadName = threadName;
this.url = url;
@@ -104,7 +108,7 @@
ExecutorService pool = Executors.newSingleThreadExecutor();
pool.execute(() -> {
- String dumpPath = url.getParameter(DUMP_DIRECTORY, System.getProperty("user.home"));
+ String dumpPath = getDumpPath();
SimpleDateFormat sdf;
@@ -134,4 +138,21 @@
}
+ private String getDumpPath() {
+ final String dumpPath = url.getParameter(DUMP_DIRECTORY);
+ if (StringUtils.isEmpty(dumpPath)) {
+ return USER_HOME;
+ }
+ final File dumpDirectory = new File(dumpPath);
+ if (!dumpDirectory.exists()) {
+ if (dumpDirectory.mkdirs()) {
+ logger.info(format("Dubbo dump directory[%s] created", dumpDirectory.getAbsolutePath()));
+ } else {
+ logger.warn(format("Dubbo dump directory[%s] can't be created, use the 'user.home'[%s]",
+ dumpDirectory.getAbsolutePath(), USER_HOME));
+ return USER_HOME;
+ }
+ }
+ return dumpPath;
+ }
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ArrayUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ArrayUtils.java
index e648598..33af1bc 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ArrayUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ArrayUtils.java
@@ -50,9 +50,7 @@
}
public static int indexOf(String[] array, String valueToFind, int startIndex) {
- if (isEmpty(array) || valueToFind == null) {
- return -1;
- } else {
+ if (!isEmpty(array) && valueToFind != null) {
if (startIndex < 0) {
startIndex = 0;
}
@@ -63,8 +61,8 @@
}
}
- return -1;
}
+ return -1;
}
/**
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java
index 1b73370..8f16036 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java
@@ -324,9 +324,7 @@
try {
return one.containsAll(another);
- } catch (ClassCastException unused) {
- return false;
- } catch (NullPointerException unused) {
+ } catch (ClassCastException | NullPointerException unused) {
return false;
}
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CompatibleTypeUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CompatibleTypeUtils.java
index 5d5cc5c..415f017 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CompatibleTypeUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CompatibleTypeUtils.java
@@ -1,223 +1,229 @@
-/*
- * 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.utils;
-
-import java.lang.reflect.Array;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-public class CompatibleTypeUtils {
-
- private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
-
- private CompatibleTypeUtils() {
- }
-
- /**
- * Compatible type convert. Null value is allowed to pass in. If no conversion is needed, then the original value
- * will be returned.
- * <p>
- * Supported compatible type conversions include (primary types and corresponding wrappers are not listed):
- * <ul>
- * <li> String -> char, enum, Date
- * <li> byte, short, int, long -> byte, short, int, long
- * <li> float, double -> float, double
- * </ul>
- */
- @SuppressWarnings({"unchecked", "rawtypes"})
- public static Object compatibleTypeConvert(Object value, Class<?> type) {
- if (value == null || type == null || type.isAssignableFrom(value.getClass())) {
- return value;
- }
-
- if (value instanceof String) {
- String string = (String) value;
- if (char.class.equals(type) || Character.class.equals(type)) {
- if (string.length() != 1) {
- throw new IllegalArgumentException(String.format("CAN NOT convert String(%s) to char!" +
- " when convert String to char, the String MUST only 1 char.", string));
- }
- return string.charAt(0);
- }
- if (type.isEnum()) {
- return Enum.valueOf((Class<Enum>) type, string);
- }
- if (type == BigInteger.class) {
- return new BigInteger(string);
- }
- if (type == BigDecimal.class) {
- return new BigDecimal(string);
- }
- if (type == Short.class || type == short.class) {
- return new Short(string);
- }
- if (type == Integer.class || type == int.class) {
- return new Integer(string);
- }
- if (type == Long.class || type == long.class) {
- return new Long(string);
- }
- if (type == Double.class || type == double.class) {
- return new Double(string);
- }
- if (type == Float.class || type == float.class) {
- return new Float(string);
- }
- if (type == Byte.class || type == byte.class) {
- return new Byte(string);
- }
- if (type == Boolean.class || type == boolean.class) {
- return Boolean.valueOf(string);
- }
- if (type == Date.class || type == java.sql.Date.class || type == java.sql.Timestamp.class
- || type == java.sql.Time.class) {
- try {
- Date date = new SimpleDateFormat(DATE_FORMAT).parse(string);
- if (type == java.sql.Date.class) {
- return new java.sql.Date(date.getTime());
- }
- if (type == java.sql.Timestamp.class) {
- return new java.sql.Timestamp(date.getTime());
- }
- if (type == java.sql.Time.class) {
- return new java.sql.Time(date.getTime());
- }
- return date;
- } catch (ParseException e) {
- throw new IllegalStateException("Failed to parse date " + value + " by format "
- + DATE_FORMAT + ", cause: " + e.getMessage(), e);
- }
- }
- if (type == java.time.LocalDateTime.class || type == java.time.LocalDate.class
- || type == java.time.LocalTime.class) {
-
- LocalDateTime localDateTime = LocalDateTime.parse(string);
- if (type == java.time.LocalDate.class) {
- return localDateTime.toLocalDate();
- }
- if (type == java.time.LocalTime.class) {
- return localDateTime.toLocalTime();
- }
- return localDateTime;
- }
- if (type == Class.class) {
- try {
- return ReflectUtils.name2class(string);
- } catch (ClassNotFoundException e) {
- throw new RuntimeException(e.getMessage(), e);
- }
- }
- if (char[].class.equals(type)) {
- // Process string to char array for generic invoke
- // See
- // - https://github.com/apache/dubbo/issues/2003
- int len = string.length();
- char[] chars = new char[len];
- string.getChars(0, len, chars, 0);
- return chars;
- }
- }
- if (value instanceof Number) {
- Number number = (Number) value;
- if (type == byte.class || type == Byte.class) {
- return number.byteValue();
- }
- if (type == short.class || type == Short.class) {
- return number.shortValue();
- }
- if (type == int.class || type == Integer.class) {
- return number.intValue();
- }
- if (type == long.class || type == Long.class) {
- return number.longValue();
- }
- if (type == float.class || type == Float.class) {
- return number.floatValue();
- }
- if (type == double.class || type == Double.class) {
- return number.doubleValue();
- }
- if (type == BigInteger.class) {
- return BigInteger.valueOf(number.longValue());
- }
- if (type == BigDecimal.class) {
- return BigDecimal.valueOf(number.doubleValue());
- }
- if (type == Date.class) {
- return new Date(number.longValue());
- }
- if (type == boolean.class || type == Boolean.class) {
- return 0 != number.intValue();
- }
- }
- if (value instanceof Collection) {
- Collection collection = (Collection) value;
- if (type.isArray()) {
- int length = collection.size();
- Object array = Array.newInstance(type.getComponentType(), length);
- int i = 0;
- for (Object item : collection) {
- Array.set(array, i++, item);
- }
- return array;
- }
- if (!type.isInterface()) {
- try {
- Collection result = (Collection) type.newInstance();
- result.addAll(collection);
- return result;
- } catch (Throwable ignored) {
- }
- }
- if (type == List.class) {
- return new ArrayList<Object>(collection);
- }
- if (type == Set.class) {
- return new HashSet<Object>(collection);
- }
- }
- if (value.getClass().isArray() && Collection.class.isAssignableFrom(type)) {
- Collection collection;
- if (!type.isInterface()) {
- try {
- collection = (Collection) type.newInstance();
- } catch (Throwable e) {
- collection = new ArrayList<Object>();
- }
- } else if (type == Set.class) {
- collection = new HashSet<Object>();
- } else {
- collection = new ArrayList<Object>();
- }
- int length = Array.getLength(value);
- for (int i = 0; i < length; i++) {
- collection.add(Array.get(value, i));
- }
- return collection;
- }
- return value;
- }
-}
+/*
+ * 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.utils;
+
+import java.lang.reflect.Array;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class CompatibleTypeUtils {
+
+ private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
+
+ private CompatibleTypeUtils() {
+ }
+
+ /**
+ * Compatible type convert. Null value is allowed to pass in. If no conversion is needed, then the original value
+ * will be returned.
+ * <p>
+ * Supported compatible type conversions include (primary types and corresponding wrappers are not listed):
+ * <ul>
+ * <li> String -> char, enum, Date
+ * <li> byte, short, int, long -> byte, short, int, long
+ * <li> float, double -> float, double
+ * </ul>
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public static Object compatibleTypeConvert(Object value, Class<?> type) {
+ if (value == null || type == null || type.isAssignableFrom(value.getClass())) {
+ return value;
+ }
+
+ if (value instanceof String) {
+ String string = (String) value;
+ if (char.class.equals(type) || Character.class.equals(type)) {
+ if (string.length() != 1) {
+ throw new IllegalArgumentException(String.format("CAN NOT convert String(%s) to char!" +
+ " when convert String to char, the String MUST only 1 char.", string));
+ }
+ return string.charAt(0);
+ }
+ if (type.isEnum()) {
+ return Enum.valueOf((Class<Enum>) type, string);
+ }
+ if (type == BigInteger.class) {
+ return new BigInteger(string);
+ }
+ if (type == BigDecimal.class) {
+ return new BigDecimal(string);
+ }
+ if (type == Short.class || type == short.class) {
+ return new Short(string);
+ }
+ if (type == Integer.class || type == int.class) {
+ return new Integer(string);
+ }
+ if (type == Long.class || type == long.class) {
+ return new Long(string);
+ }
+ if (type == Double.class || type == double.class) {
+ return new Double(string);
+ }
+ if (type == Float.class || type == float.class) {
+ return new Float(string);
+ }
+ if (type == Byte.class || type == byte.class) {
+ return new Byte(string);
+ }
+ if (type == Boolean.class || type == boolean.class) {
+ return Boolean.valueOf(string);
+ }
+ if (type == Date.class || type == java.sql.Date.class || type == java.sql.Timestamp.class
+ || type == java.sql.Time.class) {
+ try {
+ Date date = new SimpleDateFormat(DATE_FORMAT).parse(string);
+ if (type == java.sql.Date.class) {
+ return new java.sql.Date(date.getTime());
+ }
+ if (type == java.sql.Timestamp.class) {
+ return new java.sql.Timestamp(date.getTime());
+ }
+ if (type == java.sql.Time.class) {
+ return new java.sql.Time(date.getTime());
+ }
+ return date;
+ } catch (ParseException e) {
+ throw new IllegalStateException("Failed to parse date " + value + " by format "
+ + DATE_FORMAT + ", cause: " + e.getMessage(), e);
+ }
+ }
+ if (type == java.time.LocalDateTime.class) {
+ if (StringUtils.isEmpty(string)) {
+ return null;
+ }
+ return LocalDateTime.parse(string);
+ }
+ if (type == java.time.LocalDate.class) {
+ if (StringUtils.isEmpty(string)) {
+ return null;
+ }
+ return java.time.LocalDate.parse(string);
+ }
+ if (type == java.time.LocalTime.class) {
+ if (StringUtils.isEmpty(string)) {
+ return null;
+ }
+ return LocalDateTime.parse(string).toLocalTime();
+ }
+ if (type == Class.class) {
+ try {
+ return ReflectUtils.name2class(string);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+ if (char[].class.equals(type)) {
+ // Process string to char array for generic invoke
+ // See
+ // - https://github.com/apache/dubbo/issues/2003
+ int len = string.length();
+ char[] chars = new char[len];
+ string.getChars(0, len, chars, 0);
+ return chars;
+ }
+ }
+ if (value instanceof Number) {
+ Number number = (Number) value;
+ if (type == byte.class || type == Byte.class) {
+ return number.byteValue();
+ }
+ if (type == short.class || type == Short.class) {
+ return number.shortValue();
+ }
+ if (type == int.class || type == Integer.class) {
+ return number.intValue();
+ }
+ if (type == long.class || type == Long.class) {
+ return number.longValue();
+ }
+ if (type == float.class || type == Float.class) {
+ return number.floatValue();
+ }
+ if (type == double.class || type == Double.class) {
+ return number.doubleValue();
+ }
+ if (type == BigInteger.class) {
+ return BigInteger.valueOf(number.longValue());
+ }
+ if (type == BigDecimal.class) {
+ return BigDecimal.valueOf(number.doubleValue());
+ }
+ if (type == Date.class) {
+ return new Date(number.longValue());
+ }
+ if (type == boolean.class || type == Boolean.class) {
+ return 0 != number.intValue();
+ }
+ }
+ if (value instanceof Collection) {
+ Collection collection = (Collection) value;
+ if (type.isArray()) {
+ int length = collection.size();
+ Object array = Array.newInstance(type.getComponentType(), length);
+ int i = 0;
+ for (Object item : collection) {
+ Array.set(array, i++, item);
+ }
+ return array;
+ }
+ if (!type.isInterface()) {
+ try {
+ Collection result = (Collection) type.newInstance();
+ result.addAll(collection);
+ return result;
+ } catch (Throwable ignored) {
+ }
+ }
+ if (type == List.class) {
+ return new ArrayList<Object>(collection);
+ }
+ if (type == Set.class) {
+ return new HashSet<Object>(collection);
+ }
+ }
+ if (value.getClass().isArray() && Collection.class.isAssignableFrom(type)) {
+ Collection collection;
+ if (!type.isInterface()) {
+ try {
+ collection = (Collection) type.newInstance();
+ } catch (Throwable e) {
+ collection = new ArrayList<Object>();
+ }
+ } else if (type == Set.class) {
+ collection = new HashSet<Object>();
+ } else {
+ collection = new ArrayList<Object>();
+ }
+ int length = Array.getLength(value);
+ for (int i = 0; i < length; i++) {
+ collection.add(Array.get(value, i));
+ }
+ return collection;
+ }
+ return value;
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ExecutorUtil.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ExecutorUtil.java
index 93a2a60..97f13a5 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ExecutorUtil.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ExecutorUtil.java
@@ -60,9 +60,7 @@
try {
// Disable new tasks from being submitted
es.shutdown();
- } catch (SecurityException ex2) {
- return;
- } catch (NullPointerException ex2) {
+ } catch (SecurityException | NullPointerException ex2) {
return;
}
try {
@@ -86,9 +84,7 @@
final ExecutorService es = (ExecutorService) executor;
try {
es.shutdownNow();
- } catch (SecurityException ex2) {
- return;
- } catch (NullPointerException ex2) {
+ } catch (SecurityException | NullPointerException ex2) {
return;
}
try {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java
index 28cf633..4514dc8 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java
@@ -587,11 +587,7 @@
constructor.setAccessible(true);
Object[] parameters = Arrays.stream(constructor.getParameterTypes()).map(PojoUtils::getDefaultValue).toArray();
return constructor.newInstance(parameters);
- } catch (InstantiationException e) {
- throw new RuntimeException(e.getMessage(), e);
- } catch (IllegalAccessException e) {
- throw new RuntimeException(e.getMessage(), e);
- } catch (InvocationTargetException e) {
+ } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java
index a8b728b..5007287 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java
@@ -31,6 +31,7 @@
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
@@ -154,8 +155,8 @@
}
public static boolean isPrimitives(Class<?> cls) {
- if (cls.isArray()) {
- return isPrimitive(cls.getComponentType());
+ while (cls.isArray()) {
+ cls = cls.getComponentType();
}
return isPrimitive(cls);
}
@@ -1202,6 +1203,9 @@
if (actualArgType instanceof ParameterizedType) {
returnType = (Class<?>) ((ParameterizedType) actualArgType).getRawType();
genericReturnType = actualArgType;
+ } else if (actualArgType instanceof TypeVariable) {
+ returnType = (Class<?>) ((TypeVariable<?>) actualArgType).getBounds()[0];
+ genericReturnType = actualArgType;
} else {
returnType = (Class<?>) actualArgType;
genericReturnType = returnType;
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
index 970a6ae..536286c 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
@@ -26,6 +26,7 @@
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.config.support.Parameter;
import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.ServiceMetadata;
import java.util.ArrayList;
import java.util.Arrays;
@@ -53,6 +54,21 @@
private static final long serialVersionUID = -1559314110797223229L;
/**
+ * The interface name of the exported service
+ */
+ protected String interfaceName;
+ /**
+ * The remote service version the customer/provider side will reference
+ */
+ protected String version;
+
+ /**
+ * The remote service group the customer/provider side will reference
+ */
+ protected String group;
+
+ protected ServiceMetadata serviceMetadata;
+ /**
* Local impl class name for the service interface
*/
protected String local;
@@ -312,6 +328,10 @@
}
+ protected boolean notHasSelfRegistryProperty() {
+ return CollectionUtils.isEmpty(registries) && StringUtils.isEmpty(registryIds);
+ }
+
public void completeCompoundConfigs(AbstractInterfaceConfig interfaceConfig) {
if (interfaceConfig != null) {
if (application == null) {
@@ -320,15 +340,16 @@
if (module == null) {
setModule(interfaceConfig.getModule());
}
- if (registries == null) {
+ if (notHasSelfRegistryProperty()) {
setRegistries(interfaceConfig.getRegistries());
+ setRegistryIds(interfaceConfig.getRegistryIds());
}
if (monitor == null) {
setMonitor(interfaceConfig.getMonitor());
}
}
if (module != null) {
- if (registries == null) {
+ if (notHasSelfRegistryProperty()) {
setRegistries(module.getRegistries());
}
if (monitor == null) {
@@ -336,8 +357,9 @@
}
}
if (application != null) {
- if (registries == null) {
+ if (notHasSelfRegistryProperty()) {
setRegistries(application.getRegistries());
+ setRegistryIds(application.getRegistryIds());
}
if (monitor == null) {
setMonitor(application.getMonitor());
@@ -346,10 +368,9 @@
}
protected void computeValidRegistryIds() {
- if (StringUtils.isEmpty(getRegistryIds())) {
- if (getApplication() != null && StringUtils.isNotEmpty(getApplication().getRegistryIds())) {
- setRegistryIds(getApplication().getRegistryIds());
- }
+ if (application != null && notHasSelfRegistryProperty()) {
+ setRegistries(application.getRegistries());
+ setRegistryIds(application.getRegistryIds());
}
}
@@ -451,11 +472,18 @@
this.layer = layer;
}
+ /**
+ * Always use the global ApplicationConfig
+ */
public ApplicationConfig getApplication() {
- if (application != null) {
+ ApplicationConfig globalApplication = ApplicationModel.getConfigManager().getApplicationOrElseThrow();
+ if (globalApplication == null) {
return application;
}
- return ApplicationModel.getConfigManager().getApplicationOrElseThrow();
+ if (application != null && !StringUtils.isEquals(application.getName(), globalApplication.getName())) {
+ return application;
+ }
+ return globalApplication;
}
@Deprecated
@@ -685,4 +713,46 @@
public SslConfig getSslConfig() {
return ApplicationModel.getConfigManager().getSsl().orElse(null);
}
+
+ public void initServiceMetadata(AbstractInterfaceConfig interfaceConfig) {
+ serviceMetadata.setVersion(getVersion(interfaceConfig));
+ serviceMetadata.setGroup(getGroup(interfaceConfig));
+ serviceMetadata.setDefaultGroup(getGroup(interfaceConfig));
+ serviceMetadata.setServiceInterfaceName(getInterface());
+ }
+
+ public String getGroup(AbstractInterfaceConfig interfaceConfig) {
+ return StringUtils.isEmpty(this.group) ? (interfaceConfig != null ? interfaceConfig.getGroup() : this.group) : this.group;
+ }
+
+ public String getVersion(AbstractInterfaceConfig interfaceConfig) {
+ return StringUtils.isEmpty(this.version) ? (interfaceConfig != null ? interfaceConfig.getVersion() : this.version) : this.version;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public String getGroup() {
+ return group;
+ }
+
+ public void setGroup(String group) {
+ this.group = group;
+ }
+
+ public String getInterface() {
+ return interfaceName;
+ }
+
+ public void setInterface(String interfaceName) {
+ this.interfaceName = interfaceName;
+// if (StringUtils.isEmpty(id)) {
+// id = interfaceName;
+// }
+ }
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractReferenceConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractReferenceConfig.java
index 27d4ddc..f2038a1 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractReferenceConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractReferenceConfig.java
@@ -71,15 +71,7 @@
//TODO solve merge problem
protected Boolean stubevent;//= Constants.DEFAULT_STUB_EVENT;
- /**
- * The remote service version the customer side will reference
- */
- protected String version;
- /**
- * The remote service group the customer side will reference
- */
- protected String group;
/**
* declares which app or service this interface belongs to
@@ -212,21 +204,7 @@
this.sticky = sticky;
}
- public String getVersion() {
- return version;
- }
- public void setVersion(String version) {
- this.version = version;
- }
-
- public String getGroup() {
- return group;
- }
-
- public void setGroup(String group) {
- this.group = group;
- }
@Parameter(key = "provided-by")
public String getProvidedBy() {
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 e482e35..fe65c5b 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
@@ -42,6 +42,7 @@
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.REGISTRY_PUBLISH_INTERFACE_KEY;
import static org.apache.dubbo.config.Constants.DEVELOPMENT_ENVIRONMENT;
import static org.apache.dubbo.config.Constants.PRODUCTION_ENVIRONMENT;
import static org.apache.dubbo.config.Constants.TEST_ENVIRONMENT;
@@ -159,6 +160,8 @@
private String repository;
+ private Boolean publishInterface;
+
/**
* Metadata Service, used in Service Discovery
*/
@@ -450,6 +453,15 @@
this.repository = repository;
}
+ @Parameter(key = REGISTRY_PUBLISH_INTERFACE_KEY)
+ public Boolean getPublishInterface() {
+ return publishInterface;
+ }
+
+ public void setPublishInterface(Boolean publishInterface) {
+ this.publishInterface = publishInterface;
+ }
+
@Parameter(key = "metadata-service-port")
public Integer getMetadataServicePort() {
return metadataServicePort;
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/ReferenceConfigBase.java b/dubbo-common/src/main/java/org/apache/dubbo/config/ReferenceConfigBase.java
index 966b384..a16b49e 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/ReferenceConfigBase.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/ReferenceConfigBase.java
@@ -43,11 +43,6 @@
private static final long serialVersionUID = -5864351140409987595L;
/**
- * The interface name of the reference service
- */
- protected String interfaceName;
-
- /**
* The interface class of the reference service
*/
protected Class<?> interfaceClass;
@@ -72,7 +67,6 @@
*/
protected String protocol;
- protected ServiceMetadata serviceMetadata;
public ReferenceConfigBase() {
serviceMetadata = new ServiceMetadata();
@@ -160,18 +154,6 @@
setInterface(interfaceClass);
}
- public String getInterface() {
- return interfaceName;
- }
-
- public void setInterface(String interfaceName) {
- this.interfaceName = interfaceName;
- // FIXME, add id strategy in ConfigManager
-// if (StringUtils.isEmpty(id)) {
-// id = interfaceName;
-// }
- }
-
public void setInterface(Class<?> interfaceClass) {
if (interfaceClass != null && !interfaceClass.isInterface()) {
throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!");
@@ -259,12 +241,14 @@
@Override
protected void computeValidRegistryIds() {
- super.computeValidRegistryIds();
- if (StringUtils.isEmpty(getRegistryIds())) {
- if (getConsumer() != null && StringUtils.isNotEmpty(getConsumer().getRegistryIds())) {
- setRegistryIds(getConsumer().getRegistryIds());
+ if (consumer != null) {
+ if (notHasSelfRegistryProperty()) {
+ setRegistries(consumer.getRegistries());
+ setRegistryIds(consumer.getRegistryIds());
}
}
+
+ super.computeValidRegistryIds();
}
@Parameter(excluded = true)
@@ -272,16 +256,6 @@
return URL.buildKey(interfaceName, getGroup(), getVersion());
}
- @Override
- public String getVersion() {
- return StringUtils.isEmpty(this.version) ? (consumer != null ? consumer.getVersion() : this.version) : this.version;
- }
-
- @Override
- public String getGroup() {
- return StringUtils.isEmpty(this.group) ? (consumer != null ? consumer.getGroup() : this.group) : this.group;
- }
-
public abstract T get();
public abstract void destroy();
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/ServiceConfigBase.java b/dubbo-common/src/main/java/org/apache/dubbo/config/ServiceConfigBase.java
index f1b14d6..c213e49 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/ServiceConfigBase.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/ServiceConfigBase.java
@@ -43,10 +43,7 @@
private static final long serialVersionUID = 3033787999037024738L;
- /**
- * The interface name of the exported service
- */
- protected String interfaceName;
+
/**
* The interface class of the exported service
@@ -78,7 +75,7 @@
*/
protected volatile String generic;
- protected ServiceMetadata serviceMetadata;
+
public ServiceConfigBase() {
serviceMetadata = new ServiceMetadata();
@@ -202,32 +199,35 @@
}
public void checkProtocol() {
+ if (provider != null && notHasSelfProtocolProperty()) {
+ setProtocols(provider.getProtocols());
+ setProtocolIds(provider.getProtocolIds());
+ }
+
if (CollectionUtils.isEmpty(protocols) && provider != null) {
setProtocols(provider.getProtocols());
}
convertProtocolIdsToProtocols();
}
+ private boolean notHasSelfProtocolProperty() {
+ return CollectionUtils.isEmpty(protocols) && StringUtils.isEmpty(protocolIds);
+ }
+
public void completeCompoundConfigs() {
super.completeCompoundConfigs(provider);
if (provider != null) {
- if (protocols == null) {
+ if (notHasSelfProtocolProperty()) {
setProtocols(provider.getProtocols());
+ setProtocolIds(provider.getProtocolIds());
}
if (configCenter == null) {
setConfigCenter(provider.getConfigCenter());
}
- if (StringUtils.isEmpty(registryIds)) {
- setRegistryIds(provider.getRegistryIds());
- }
- if (StringUtils.isEmpty(protocolIds)) {
- setProtocolIds(provider.getProtocolIds());
- }
}
}
private void convertProtocolIdsToProtocols() {
- computeValidProtocolIds();
if (StringUtils.isEmpty(protocolIds)) {
if (CollectionUtils.isEmpty(protocols)) {
List<ProtocolConfig> protocolConfigs = ApplicationModel.getConfigManager().getDefaultProtocols();
@@ -292,9 +292,7 @@
setInterface(interfaceClass);
}
- public String getInterface() {
- return interfaceName;
- }
+
public void setInterface(Class<?> interfaceClass) {
if (interfaceClass != null && !interfaceClass.isInterface()) {
@@ -304,14 +302,6 @@
setInterface(interfaceClass == null ? null : interfaceClass.getName());
}
- public void setInterface(String interfaceName) {
- this.interfaceName = interfaceName;
- // FIXME, add id strategy in ConfigManager
-// if (StringUtils.isEmpty(id)) {
-// id = interfaceName;
-// }
- }
-
public T getRef() {
return ref;
}
@@ -403,32 +393,16 @@
return URL.buildKey(interfaceName, getGroup(), getVersion());
}
- @Override
- public String getGroup() {
- return StringUtils.isEmpty(this.group) ? (provider != null ? provider.getGroup() : this.group) : this.group;
- }
- @Override
- public String getVersion() {
- return StringUtils.isEmpty(this.version) ? (provider != null ? provider.getVersion() : this.version) : this.version;
- }
-
- private void computeValidProtocolIds() {
- if (StringUtils.isEmpty(getProtocolIds())) {
- if (getProvider() != null && StringUtils.isNotEmpty(getProvider().getProtocolIds())) {
- setProtocolIds(getProvider().getProtocolIds());
- }
- }
- }
@Override
protected void computeValidRegistryIds() {
- super.computeValidRegistryIds();
- if (StringUtils.isEmpty(getRegistryIds())) {
- if (getProvider() != null && StringUtils.isNotEmpty(getProvider().getRegistryIds())) {
- setRegistryIds(getProvider().getRegistryIds());
- }
+ if (provider != null && notHasSelfRegistryProperty()) {
+ setRegistries(provider.getRegistries());
+ setRegistryIds(provider.getRegistryIds());
}
+
+ super.computeValidRegistryIds();
}
public abstract void export();
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoaderTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoaderTest.java
index a1a534a..b861fc0 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoaderTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoaderTest.java
@@ -374,7 +374,7 @@
fail();
} catch (IllegalStateException expected) {
assertThat(expected.getMessage(), containsString("Failed to load extension class (interface: interface org.apache.dubbo.common.extension.ext7.InitErrorExt"));
- assertThat(expected.getCause(), instanceOf(ExceptionInInitializerError.class));
+ assertThat(expected.getMessage(), containsString("java.lang.ExceptionInInitializerError"));
}
}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/manager/ExecutorRepositoryTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/manager/ExecutorRepositoryTest.java
index bb3fe4e..b19eb37 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/manager/ExecutorRepositoryTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/manager/ExecutorRepositoryTest.java
@@ -39,8 +39,6 @@
}
private void testGet(URL url) {
- Assertions.assertNull(executorRepository.getExecutor(url));
-
ExecutorService executorService = executorRepository.createExecutorIfAbsent(url);
executorService.shutdown();
executorService = executorRepository.createExecutorIfAbsent(url);
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..178c73a 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,9 +17,9 @@
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.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
@@ -44,4 +44,60 @@
Thread.sleep(1000);
}
+
+ @Test
+ public void jStackDumpTest_dumpDirectoryNotExists_cannotBeCreatedTakeUserHome() throws InterruptedException {
+ final String dumpDirectory = dumpDirectoryCannotBeCreated();
+
+ URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?dump.directory="
+ + dumpDirectory
+ + "&version=1.0.0&application=morgan&noValue");
+ AbortPolicyWithReport abortPolicyWithReport = new AbortPolicyWithReport("Test", url);
+
+ try {
+ abortPolicyWithReport.rejectedExecution(new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("hello");
+ }
+ }, (ThreadPoolExecutor) Executors.newFixedThreadPool(1));
+ } catch (RejectedExecutionException rj) {
+ // ignore
+ }
+
+ Thread.sleep(1000);
+ }
+
+ private String dumpDirectoryCannotBeCreated() {
+ final String os = System.getProperty("os.name").toLowerCase();
+ if (os.contains("win")) {
+ // "con" is one of Windows reserved names, https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
+ return "con";
+ } else {
+ return "/dev/full/" + UUID.randomUUID().toString();
+ }
+ }
+
+ @Test
+ public void jStackDumpTest_dumpDirectoryNotExists_canBeCreated() throws InterruptedException {
+ final String dumpDirectory = UUID.randomUUID().toString();
+
+ URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?dump.directory="
+ + dumpDirectory
+ + "&version=1.0.0&application=morgan&noValue");
+ AbortPolicyWithReport abortPolicyWithReport = new AbortPolicyWithReport("Test", url);
+
+ try {
+ abortPolicyWithReport.rejectedExecution(new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("hello");
+ }
+ }, (ThreadPoolExecutor) Executors.newFixedThreadPool(1));
+ } catch (RejectedExecutionException rj) {
+ // ignore
+ }
+
+ Thread.sleep(1000);
+ }
}
\ No newline at end of file
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/CompatibleTypeUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/CompatibleTypeUtilsTest.java
index 85e7180..eaae795 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/CompatibleTypeUtilsTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/CompatibleTypeUtilsTest.java
@@ -84,7 +84,7 @@
result = CompatibleTypeUtils.compatibleTypeConvert("2011-12-11T12:24:12.047", java.time.LocalTime.class);
assertEquals(DateTimeFormatter.ofPattern("HH:mm:ss").format((java.time.LocalTime) result), "12:24:12");
- result = CompatibleTypeUtils.compatibleTypeConvert("2011-12-11T12:24:12.047", java.time.LocalDate.class);
+ result = CompatibleTypeUtils.compatibleTypeConvert("2011-12-11", java.time.LocalDate.class);
assertEquals(DateTimeFormatter.ofPattern("yyyy-MM-dd").format((java.time.LocalDate) result), "2011-12-11");
result = CompatibleTypeUtils.compatibleTypeConvert("ab", char[].class);
@@ -219,4 +219,4 @@
}
}
-}
\ No newline at end of file
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/PojoUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/PojoUtilsTest.java
index 4bc4b31..e615dd9 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/PojoUtilsTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/PojoUtilsTest.java
@@ -199,6 +199,11 @@
assertArrayObject(new Float[]{37F, -39F, 123456.7F});
assertArrayObject(new Double[]{37D, -39D, 123456.7D});
+
+ assertObject(new int[][]{{37, -39, 12456}});
+ assertObject(new Integer[][][]{{{37, -39, 12456}}});
+
+ assertArrayObject(new Integer[]{37, -39, 12456});
}
@Test
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ReflectUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ReflectUtilsTest.java
index 6b6b7f6..d9adde8 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ReflectUtilsTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ReflectUtilsTest.java
@@ -416,18 +416,44 @@
Assertions.assertEquals("java.lang.String", types1[0].getTypeName());
Assertions.assertEquals("java.lang.String", types1[1].getTypeName());
- Type[] types2 = ReflectUtils.getReturnTypes(clazz.getMethod("getListFuture"));
- Assertions.assertEquals("java.util.List", types2[0].getTypeName());
- Assertions.assertEquals("java.util.List<java.lang.String>", types2[1].getTypeName());
+ Type[] types2 = ReflectUtils.getReturnTypes(clazz.getMethod("getT"));
+ Assertions.assertEquals("java.lang.String", types2[0].getTypeName());
+ Assertions.assertEquals("T", types2[1].getTypeName());
+
+ Type[] types3 = ReflectUtils.getReturnTypes(clazz.getMethod("getS"));
+ Assertions.assertEquals("java.lang.Object", types3[0].getTypeName());
+ Assertions.assertEquals("S", types3[1].getTypeName());
+
+ Type[] types4 = ReflectUtils.getReturnTypes(clazz.getMethod("getListFuture"));
+ Assertions.assertEquals("java.util.List", types4[0].getTypeName());
+ Assertions.assertEquals("java.util.List<java.lang.String>", types4[1].getTypeName());
+
+ Type[] types5 = ReflectUtils.getReturnTypes(clazz.getMethod("getGenericWithUpperFuture"));
+ // T extends String, the first arg should be the upper bound of param
+ Assertions.assertEquals("java.lang.String", types5[0].getTypeName());
+ Assertions.assertEquals("T", types5[1].getTypeName());
+
+ Type[] types6 = ReflectUtils.getReturnTypes(clazz.getMethod("getGenericFuture"));
+ // default upper bound is Object
+ Assertions.assertEquals("java.lang.Object", types6[0].getTypeName());
+ Assertions.assertEquals("S", types6[1].getTypeName());
}
- public interface TypeClass {
+ public interface TypeClass<T extends String, S> {
CompletableFuture<String> getFuture();
String getString();
+ T getT();
+
+ S getS();
+
CompletableFuture<List<String>> getListFuture();
+
+ CompletableFuture<T> getGenericWithUpperFuture();
+
+ CompletableFuture<S> getGenericFuture();
}
public static class EmptyClass {
diff --git a/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/FutureAdapter.java b/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/FutureAdapter.java
index 29cc14a..b2bba70 100644
--- a/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/FutureAdapter.java
+++ b/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/FutureAdapter.java
@@ -66,9 +66,7 @@
public Object get() throws RemotingException {
try {
return future.get();
- } catch (InterruptedException e) {
- throw new RemotingException(e);
- } catch (ExecutionException e) {
+ } catch (InterruptedException | ExecutionException e) {
throw new RemotingException(e);
}
}
@@ -77,11 +75,7 @@
public Object get(int timeoutInMillis) throws RemotingException {
try {
return future.get(timeoutInMillis, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- throw new RemotingException(e);
- } catch (ExecutionException e) {
- throw new RemotingException(e);
- } catch (TimeoutException e) {
+ } catch (InterruptedException | TimeoutException | ExecutionException e) {
throw new RemotingException(e);
}
}
diff --git a/dubbo-compatible/src/test/java/org/apache/dubbo/generic/GenericServiceTest.java b/dubbo-compatible/src/test/java/org/apache/dubbo/generic/GenericServiceTest.java
index ec9a08e..7b012d4 100644
--- a/dubbo-compatible/src/test/java/org/apache/dubbo/generic/GenericServiceTest.java
+++ b/dubbo-compatible/src/test/java/org/apache/dubbo/generic/GenericServiceTest.java
@@ -18,6 +18,7 @@
package org.apache.dubbo.generic;
+import com.alibaba.dubbo.config.ReferenceConfig;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder;
@@ -89,6 +90,29 @@
}
@Test
+ public void testGenericCompatible() {
+ DemoService server = new DemoServiceImpl();
+ ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
+ Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
+ URL url = URL.valueOf("dubbo://127.0.0.1:5342/" + DemoService.class.getName() + "?version=1.0.0&generic=true$timeout=3000");
+ Exporter<DemoService> exporter = protocol.export(proxyFactory.getInvoker(server, DemoService.class, url));
+
+ // simulate normal invoke
+ ReferenceConfig<com.alibaba.dubbo.rpc.service.GenericService> oldReferenceConfig = new ReferenceConfig<>();
+ oldReferenceConfig.setGeneric(true);
+ oldReferenceConfig.setInterface(DemoService.class.getName());
+ oldReferenceConfig.checkAndUpdateSubConfigs();
+ Invoker invoker = protocol.refer(oldReferenceConfig.getInterfaceClass(), url);
+ com.alibaba.dubbo.rpc.service.GenericService client = (com.alibaba.dubbo.rpc.service.GenericService) proxyFactory.getProxy(invoker, true);
+
+ Object result = client.$invoke("sayHello", new String[]{"java.lang.String"}, new Object[]{"haha"});
+ Assertions.assertEquals("hello haha", result);
+
+ invoker.destroy();
+ exporter.unexport();
+ }
+
+ @Test
public void testGenericComplexCompute4FullServiceMetadata() {
DemoService server = new DemoServiceImpl();
ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
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 6445588..cbb15ac 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
@@ -424,11 +424,6 @@
throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");
}
completeCompoundConfigs(consumer);
- if (consumer != null) {
- if (StringUtils.isEmpty(registryIds)) {
- setRegistryIds(consumer.getRegistryIds());
- }
- }
// get consumer's global configuration
checkDefault();
@@ -453,12 +448,8 @@
checkInterfaceAndMethods(interfaceClass, getMethods());
}
- //init serivceMetadata
- serviceMetadata.setVersion(getVersion());
- serviceMetadata.setGroup(getGroup());
- serviceMetadata.setDefaultGroup(getGroup());
+ initServiceMetadata(consumer);
serviceMetadata.setServiceType(getActualInterface());
- serviceMetadata.setServiceInterfaceName(interfaceName);
// TODO, uncomment this line once service key is unified
serviceMetadata.setServiceKey(URL.buildKey(interfaceName, group, version));
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 8314842..e95fa08 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
@@ -189,12 +189,8 @@
checkAndUpdateSubConfigs();
- //init serviceMetadata
- serviceMetadata.setVersion(getVersion());
- serviceMetadata.setGroup(getGroup());
- serviceMetadata.setDefaultGroup(getGroup());
+ initServiceMetadata(provider);
serviceMetadata.setServiceType(getInterfaceClass());
- serviceMetadata.setServiceInterfaceName(getInterface());
serviceMetadata.setTarget(getRef());
if (!shouldExport()) {
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java
index f8f1bc9..4983dfe 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java
@@ -1180,11 +1180,18 @@
private void doRegisterServiceInstance(ServiceInstance serviceInstance) {
//FIXME
+ if (logger.isInfoEnabled()) {
+ logger.info("Start publishing metadata to remote center, this only makes sense for applications enabled remote metadata center.");
+ }
publishMetadataToRemote(serviceInstance);
+ logger.info("Start registering instance address to registry.");
getServiceDiscoveries().forEach(serviceDiscovery ->
{
calInstanceRevision(serviceDiscovery, serviceInstance);
+ if (logger.isDebugEnabled()) {
+ logger.info("Start registering instance address to registry" + serviceDiscovery.getUrl() + ", instance " + serviceInstance);
+ }
// register metadata
serviceDiscovery.register(serviceInstance);
});
@@ -1262,7 +1269,7 @@
destroyRegistries();
DubboShutdownHook.destroyProtocols();
destroyServiceDiscoveries();
-
+ destroyExecutorRepository();
clear();
shutdown();
release();
@@ -1275,6 +1282,10 @@
}
}
+ private void destroyExecutorRepository() {
+ ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension().destroyAll();
+ }
+
private void destroyRegistries() {
AbstractRegistryFactory.destroyAll();
}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java
index d7d60fc..fdb011f 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java
@@ -20,8 +20,6 @@
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.config.ApplicationConfig;
-import org.apache.dubbo.config.ArgumentConfig;
-import org.apache.dubbo.config.MethodConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
@@ -31,11 +29,10 @@
import org.apache.dubbo.rpc.model.ApplicationModel;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import static java.util.Collections.emptyList;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
/**
* {@link MetadataServiceExporter} implementation based on {@link ConfigManager Dubbo configurations}, the clients
@@ -77,7 +74,6 @@
serviceConfig.setRef(metadataService);
serviceConfig.setGroup(getApplicationConfig().getName());
serviceConfig.setVersion(metadataService.version());
- serviceConfig.setMethods(generateMethodConfig());
// export
serviceConfig.export();
@@ -97,28 +93,6 @@
return this;
}
- /**
- * Generate Method Config for Service Discovery Metadata <p/>
- * <p>
- * Make {@link MetadataService} support argument callback,
- * used to notify {@link org.apache.dubbo.registry.client.ServiceInstance}'s
- * metadata change event
- *
- * @since 3.0
- */
- private List<MethodConfig> generateMethodConfig() {
- MethodConfig methodConfig = new MethodConfig();
- methodConfig.setName("getAndListenServiceDiscoveryMetadata");
-
- ArgumentConfig argumentConfig = new ArgumentConfig();
- argumentConfig.setIndex(1);
- argumentConfig.setCallback(true);
-
- methodConfig.setArguments(Collections.singletonList(argumentConfig));
-
- return Collections.singletonList(methodConfig);
- }
-
@Override
public ConfigurableMetadataServiceExporter unexport() {
if (isExported()) {
@@ -146,27 +120,10 @@
private ProtocolConfig generateMetadataProtocol() {
ProtocolConfig defaultProtocol = new ProtocolConfig();
- Integer port = getApplicationConfig().getMetadataServicePort();
-
- if (port == null || port < -1) {
- if (logger.isInfoEnabled()) {
- logger.info("Metadata Service Port hasn't been set. " +
- "Use default protocol defined in protocols.");
- }
- List<ProtocolConfig> defaultProtocols = ApplicationModel.getConfigManager().getDefaultProtocols();
-
- if (defaultProtocols.isEmpty()) {
- defaultProtocol.setName(DUBBO_PROTOCOL);
- defaultProtocol.setPort(-1);
- } else {
- return defaultProtocols.get(0);
- }
-
- } else {
- defaultProtocol.setName(DUBBO_PROTOCOL);
- defaultProtocol.setPort(port);
- }
-
+ defaultProtocol.setName(DUBBO);
+ // defaultProtocol.setHost() ?
+ // auto-increment port
+ defaultProtocol.setPort(-1);
return defaultProtocol;
}
}
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 a62e9b2..5f3bd1c 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
@@ -18,6 +18,7 @@
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.URLBuilder;
+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;
@@ -88,9 +89,10 @@
import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_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.REGISTRY_DUPLICATE_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.DUBBO_PUBLISH_INTERFACE_DEFAULT_KEY;
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.REGISTRY_PUBLISH_INTERFACE_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_PROTOCOL;
import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;
@@ -220,7 +222,7 @@
if (provider) {
// for registries enabled service discovery, automatically register interface compatible addresses.
if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())
- && registryURL.getParameter(REGISTRY_DUPLICATE_KEY, false)
+ && registryURL.getParameter(REGISTRY_PUBLISH_INTERFACE_KEY, ConfigurationUtils.getDynamicGlobalConfiguration().getBoolean(DUBBO_PUBLISH_INTERFACE_DEFAULT_KEY, false))
&& registryNotExists(registryURL, registryList, REGISTRY_PROTOCOL)) {
URL interfaceCompatibleRegistryURL = URLBuilder.from(registryURL)
.setProtocol(REGISTRY_PROTOCOL)
diff --git a/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.event.EventListener b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.event.EventListener
index db73041..3d90c3b 100644
--- a/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.event.EventListener
+++ b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.event.EventListener
@@ -1,2 +1 @@
-service-mapping=org.apache.dubbo.config.event.listener.ServiceNameMappingListener
-config-logging=org.apache.dubbo.config.event.listener.LoggingEventListener
\ No newline at end of file
+config-logging=org.apache.dubbo.config.event.listener.LoggingEventListener
diff --git a/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataServiceExporter b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataServiceExporter
index 1b843b6..2bda3f2 100644
--- a/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataServiceExporter
+++ b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataServiceExporter
@@ -1,3 +1,2 @@
# since 2.7.8
local = org.apache.dubbo.config.metadata.ConfigurableMetadataServiceExporter
-remote = org.apache.dubbo.config.metadata.RemoteMetadataServiceExporter
\ No newline at end of file
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..95c7a0b 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
@@ -160,6 +160,7 @@
assertThat(service2.getExportedUrls(), hasSize(1));
assertEquals(2, TestProxyFactory.count); // local injvm and registry protocol, so expected is 2
+ TestProxyFactory.count = 0;
}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/rest/UserService.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/rest/UserService.java
index fa5b7ae..6c32912 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/rest/UserService.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/rest/UserService.java
@@ -19,7 +19,7 @@
package org.apache.dubbo.config.bootstrap.rest;
-import org.apache.dubbo.rpc.protocol.rest.support.ContentType;
+//import org.apache.dubbo.rpc.protocol.rest.support.ContentType;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -29,12 +29,11 @@
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("users")
@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
-@Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
+//@Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
@Api(value = "UserService")
public interface UserService {
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/InvokerSideConfigUrlTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/InvokerSideConfigUrlTest.java
index c380963..1850b90 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/InvokerSideConfigUrlTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/InvokerSideConfigUrlTest.java
@@ -151,7 +151,7 @@
verifyInvokerUrlGeneration(consumerConf, consumerConfTable);
}
- @Test
+ //@Test
public void refConfUrlTest() {
verifyInvokerUrlGeneration(refConf, refConfTable);
}
diff --git a/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.registry.RegistryFactory b/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.registry.RegistryFactory
index 7b8cf68..ded0832 100644
--- a/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.registry.RegistryFactory
+++ b/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.registry.RegistryFactory
@@ -1,2 +1,3 @@
mockregistry=org.apache.dubbo.config.mock.MockRegistryFactory
mockprotocol2=org.apache.dubbo.config.mock.MockRegistryFactory2
+test=org.apache.dubbo.config.mock.MockRegistryFactory
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceClassPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceClassPostProcessor.java
index b1c9a30..4942ed7 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceClassPostProcessor.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceClassPostProcessor.java
@@ -24,7 +24,6 @@
import org.apache.dubbo.config.annotation.Method;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.config.spring.ServiceBean;
-import org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener;
import org.apache.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner;
import org.apache.dubbo.config.spring.schema.AnnotationBeanDefinitionParser;
@@ -68,7 +67,6 @@
import java.util.Objects;
import java.util.Set;
-import static com.alibaba.spring.util.BeanRegistrar.registerInfrastructureBean;
import static com.alibaba.spring.util.ObjectUtils.of;
import static java.util.Arrays.asList;
import static org.apache.dubbo.config.spring.beans.factory.annotation.ServiceBeanNameBuilder.create;
@@ -125,9 +123,6 @@
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
- // @since 2.7.5
- registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME, DubboBootstrapApplicationListener.class);
-
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
diff --git a/dubbo-configcenter/dubbo-configcenter-consul/src/test/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfigurationTest.java b/dubbo-configcenter/dubbo-configcenter-consul/src/test/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfigurationTest.java
index c54d103..60112b9 100644
--- a/dubbo-configcenter/dubbo-configcenter-consul/src/test/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfigurationTest.java
+++ b/dubbo-configcenter/dubbo-configcenter-consul/src/test/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfigurationTest.java
@@ -1,123 +1,123 @@
-/*
- * 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.configcenter.consul;
-
-import org.apache.dubbo.common.URL;
-
-import com.google.common.net.HostAndPort;
-import com.orbitz.consul.Consul;
-import com.orbitz.consul.KeyValueClient;
-import com.orbitz.consul.cache.KVCache;
-import com.orbitz.consul.model.kv.Value;
-import com.pszymczyk.consul.ConsulProcess;
-import com.pszymczyk.consul.ConsulStarterBuilder;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-
-import java.util.Arrays;
-import java.util.Optional;
-import java.util.TreeSet;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-/**
- *
- */
-public class ConsulDynamicConfigurationTest {
-
- private static ConsulProcess consul;
- private static URL configCenterUrl;
- private static ConsulDynamicConfiguration configuration;
-
- private static Consul client;
- private static KeyValueClient kvClient;
-
- @BeforeAll
- public static void setUp() throws Exception {
- consul = ConsulStarterBuilder.consulStarter()
- .build()
- .start();
- configCenterUrl = URL.valueOf("consul://127.0.0.1:" + consul.getHttpPort());
-
- configuration = new ConsulDynamicConfiguration(configCenterUrl);
- client = Consul.builder().withHostAndPort(HostAndPort.fromParts("127.0.0.1", consul.getHttpPort())).build();
- kvClient = client.keyValueClient();
- }
-
- @AfterAll
- public static void tearDown() throws Exception {
- consul.close();
- configuration.close();
- }
-
- @Test
- public void testGetConfig() {
- kvClient.putValue("/dubbo/config/dubbo/foo", "bar");
- // test equals
- assertEquals("bar", configuration.getConfig("foo", "dubbo"));
- // test does not block
- assertEquals("bar", configuration.getConfig("foo", "dubbo"));
- Assertions.assertNull(configuration.getConfig("not-exist", "dubbo"));
- }
-
- @Test
- public void testPublishConfig() {
- configuration.publishConfig("value", "metadata", "1");
- // test equals
- assertEquals("1", configuration.getConfig("value", "/metadata"));
- assertEquals("1", kvClient.getValueAsString("/dubbo/config/metadata/value").get());
- }
-
- @Test
- public void testAddListener() {
- KVCache cache = KVCache.newCache(kvClient, "/dubbo/config/dubbo/foo");
- cache.addListener(newValues -> {
- // Cache notifies all paths with "foo" the root path
- // If you want to watch only "foo" value, you must filter other paths
- Optional<Value> newValue = newValues.values().stream()
- .filter(value -> value.getKey().equals("foo"))
- .findAny();
-
- newValue.ifPresent(value -> {
- // Values are encoded in key/value store, decode it if needed
- Optional<String> decodedValue = newValue.get().getValueAsString();
- decodedValue.ifPresent(v -> System.out.println(String.format("Value is: %s", v))); //prints "bar"
- });
- });
- cache.start();
-
- kvClient.putValue("/dubbo/config/dubbo/foo", "new-value");
- kvClient.putValue("/dubbo/config/dubbo/foo/sub", "sub-value");
- kvClient.putValue("/dubbo/config/dubbo/foo/sub2", "sub-value2");
- kvClient.putValue("/dubbo/config/foo", "parent-value");
-
- System.out.println(kvClient.getKeys("/dubbo/config/dubbo/foo"));
- System.out.println(kvClient.getKeys("/dubbo/config"));
- System.out.println(kvClient.getValues("/dubbo/config/dubbo/foo"));
- }
-
- @Test
- public void testGetConfigKeys() {
- configuration.publishConfig("v1", "metadata", "1");
- configuration.publishConfig("v2", "metadata", "2");
- configuration.publishConfig("v3", "metadata", "3");
- // test equals
- assertEquals(new TreeSet(Arrays.asList("v1", "v2", "v3")), configuration.getConfigKeys("metadata"));
- }
-}
+///*
+// * 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.configcenter.consul;
+//
+//import org.apache.dubbo.common.URL;
+//
+//import com.google.common.net.HostAndPort;
+//import com.orbitz.consul.Consul;
+//import com.orbitz.consul.KeyValueClient;
+//import com.orbitz.consul.cache.KVCache;
+//import com.orbitz.consul.model.kv.Value;
+//import com.pszymczyk.consul.ConsulProcess;
+//import com.pszymczyk.consul.ConsulStarterBuilder;
+//import org.junit.jupiter.api.AfterAll;
+//import org.junit.jupiter.api.Assertions;
+//import org.junit.jupiter.api.BeforeAll;
+//import org.junit.jupiter.api.Test;
+//
+//import java.util.Arrays;
+//import java.util.Optional;
+//import java.util.TreeSet;
+//
+//import static org.junit.jupiter.api.Assertions.assertEquals;
+//
+///**
+// *
+// */
+//public class ConsulDynamicConfigurationTest {
+//
+// private static ConsulProcess consul;
+// private static URL configCenterUrl;
+// private static ConsulDynamicConfiguration configuration;
+//
+// private static Consul client;
+// private static KeyValueClient kvClient;
+//
+// @BeforeAll
+// public static void setUp() throws Exception {
+// consul = ConsulStarterBuilder.consulStarter()
+// .build()
+// .start();
+// configCenterUrl = URL.valueOf("consul://127.0.0.1:" + consul.getHttpPort());
+//
+// configuration = new ConsulDynamicConfiguration(configCenterUrl);
+// client = Consul.builder().withHostAndPort(HostAndPort.fromParts("127.0.0.1", consul.getHttpPort())).build();
+// kvClient = client.keyValueClient();
+// }
+//
+// @AfterAll
+// public static void tearDown() throws Exception {
+// consul.close();
+// configuration.close();
+// }
+//
+// @Test
+// public void testGetConfig() {
+// kvClient.putValue("/dubbo/config/dubbo/foo", "bar");
+// // test equals
+// assertEquals("bar", configuration.getConfig("foo", "dubbo"));
+// // test does not block
+// assertEquals("bar", configuration.getConfig("foo", "dubbo"));
+// Assertions.assertNull(configuration.getConfig("not-exist", "dubbo"));
+// }
+//
+// @Test
+// public void testPublishConfig() {
+// configuration.publishConfig("value", "metadata", "1");
+// // test equals
+// assertEquals("1", configuration.getConfig("value", "/metadata"));
+// assertEquals("1", kvClient.getValueAsString("/dubbo/config/metadata/value").get());
+// }
+//
+// @Test
+// public void testAddListener() {
+// KVCache cache = KVCache.newCache(kvClient, "/dubbo/config/dubbo/foo");
+// cache.addListener(newValues -> {
+// // Cache notifies all paths with "foo" the root path
+// // If you want to watch only "foo" value, you must filter other paths
+// Optional<Value> newValue = newValues.values().stream()
+// .filter(value -> value.getKey().equals("foo"))
+// .findAny();
+//
+// newValue.ifPresent(value -> {
+// // Values are encoded in key/value store, decode it if needed
+// Optional<String> decodedValue = newValue.get().getValueAsString();
+// decodedValue.ifPresent(v -> System.out.println(String.format("Value is: %s", v))); //prints "bar"
+// });
+// });
+// cache.start();
+//
+// kvClient.putValue("/dubbo/config/dubbo/foo", "new-value");
+// kvClient.putValue("/dubbo/config/dubbo/foo/sub", "sub-value");
+// kvClient.putValue("/dubbo/config/dubbo/foo/sub2", "sub-value2");
+// kvClient.putValue("/dubbo/config/foo", "parent-value");
+//
+// System.out.println(kvClient.getKeys("/dubbo/config/dubbo/foo"));
+// System.out.println(kvClient.getKeys("/dubbo/config"));
+// System.out.println(kvClient.getValues("/dubbo/config/dubbo/foo"));
+// }
+//
+// @Test
+// public void testGetConfigKeys() {
+// configuration.publishConfig("v1", "metadata", "1");
+// configuration.publishConfig("v2", "metadata", "2");
+// configuration.publishConfig("v3", "metadata", "3");
+// // test equals
+// assertEquals(new TreeSet(Arrays.asList("v1", "v2", "v3")), configuration.getConfigKeys("metadata"));
+// }
+//}
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..1b0a823 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 @@
*/
@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-consumer/pom.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml
index 6a03ac7..1e5a7d5 100644
--- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml
+++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml
@@ -36,6 +36,10 @@
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-metadata-report-failover</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-demo-interface</artifactId>
<version>${project.parent.version}</version>
</dependency>
@@ -87,5 +91,12 @@
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-jdk</artifactId>
</dependency>
+ <!-- The metadata center cannot be initialized without this dependency -->
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ <version>1.9.12</version>
+ </dependency>
+
</dependencies>
</project>
diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/spring/dubbo-consumer.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/spring/dubbo-consumer.xml
index 9225959..9c632b8 100644
--- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/spring/dubbo-consumer.xml
+++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/spring/dubbo-consumer.xml
@@ -1,39 +1,39 @@
-<?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 name="demo-consumer">
- <dubbo:parameter key="mapping-type" value="metadata"/>
- <dubbo:parameter key="enable-auto-migration" value="true"/>
- </dubbo:application>
-
- <!-- <dubbo:metadata-report address="zookeeper://127.0.0.1:2181"/>-->
-
- <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
-
- <dubbo:reference provided-by="demo-provider" id="demoService" check="false"
- interface="org.apache.dubbo.demo.DemoService"/>
-
- <dubbo:reference provided-by="demo-provider" version="1.0.0" group="greeting" id="greetingService" check="false"
- interface="org.apache.dubbo.demo.GreetingService"/>
-
-</beans>
+<?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 name="demo-consumer" >
+ <dubbo:parameter key="mapping-type" value="metadata"/>
+ <dubbo:parameter key="enable-auto-migration" value="true"/>
+ </dubbo:application>
+
+ <dubbo:metadata-report address="zookeeper://127.0.1:2181"/>
+
+ <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
+
+ <dubbo:reference id="demoService" check="true"
+ interface="org.apache.dubbo.demo.DemoService"/>
+
+ <dubbo:reference version="1.0.0" group="greeting" id="greetingService" check="false"
+ interface="org.apache.dubbo.demo.GreetingService"/>
+
+</beans>
diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml
index 65ddaba..438c542 100644
--- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml
+++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml
@@ -72,6 +72,10 @@
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-metadata-report-failover</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-dubbo</artifactId>
</dependency>
<dependency>
@@ -107,5 +111,13 @@
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
+
+ <!-- The metadata center cannot be initialized without this dependency -->
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ <version>1.9.12</version>
+ </dependency>
+
</dependencies>
</project>
diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/spring/dubbo-provider.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/spring/dubbo-provider.xml
index 0628180..05d6f8f 100644
--- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/spring/dubbo-provider.xml
+++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/spring/dubbo-provider.xml
@@ -21,7 +21,7 @@
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 name="demo-provider">
+ <dubbo:application name="demo-provider" metadata-type="remote">
<dubbo:parameter key="mapping-type" value="metadata"/>
</dubbo:application>
diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml
index 3b14893..8543170 100644
--- a/dubbo-dependencies-bom/pom.xml
+++ b/dubbo-dependencies-bom/pom.xml
@@ -153,7 +153,7 @@
<jaxb_version>2.2.7</jaxb_version>
<activation_version>1.2.0</activation_version>
- <test_container_version>1.11.2</test_container_version>
+ <test_container_version>1.15.2</test_container_version>
<etcd_launcher_version>0.5.3</etcd_launcher_version>
<hessian_lite_version>3.2.8</hessian_lite_version>
<swagger_version>1.5.19</swagger_version>
@@ -165,7 +165,7 @@
<mortbay_jetty_version>6.1.26</mortbay_jetty_version>
<portlet_version>2.0</portlet_version>
<maven_flatten_version>1.1.0</maven_flatten_version>
- <revision>2.7.9</revision>
+ <revision>2.7.10-SNAPSHOT</revision>
</properties>
<dependencyManagement>
diff --git a/dubbo-dependencies/dubbo-dependencies-zookeeper/pom.xml b/dubbo-dependencies/dubbo-dependencies-zookeeper/pom.xml
index 8a01603..fea1cb0 100644
--- a/dubbo-dependencies/dubbo-dependencies-zookeeper/pom.xml
+++ b/dubbo-dependencies/dubbo-dependencies-zookeeper/pom.xml
@@ -32,7 +32,7 @@
<packaging>pom</packaging>
<properties>
- <revision>2.7.9</revision>
+ <revision>2.7.10-SNAPSHOT</revision>
<maven_flatten_version>1.1.0</maven_flatten_version>
</properties>
@@ -51,7 +51,7 @@
<dependencies>
<dependency>
<groupId>org.apache.curator</groupId>
- <artifactId>curator-recipes</artifactId>
+ <artifactId>curator-x-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
diff --git a/dubbo-filter/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/expiring/ExpiringMap.java b/dubbo-filter/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/expiring/ExpiringMap.java
index 895f114..326b51e 100644
--- a/dubbo-filter/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/expiring/ExpiringMap.java
+++ b/dubbo-filter/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/expiring/ExpiringMap.java
@@ -137,6 +137,9 @@
@Override
public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
return delegateMap.equals(obj);
}
@@ -226,6 +229,9 @@
@Override
public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
return value.equals(obj);
}
@@ -282,10 +288,10 @@
private void processExpires() {
long timeNow = System.currentTimeMillis();
+ if (timeToLiveMillis <= 0) {
+ return;
+ }
for (ExpiryObject o : delegateMap.values()) {
- if (timeToLiveMillis <= 0) {
- continue;
- }
long timeIdle = timeNow - o.getLastAccessTime();
if (timeIdle >= timeToLiveMillis) {
delegateMap.remove(o.getKey());
diff --git a/dubbo-filter/dubbo-filter-cache/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.cache.CacheFactory b/dubbo-filter/dubbo-filter-cache/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.cache.CacheFactory
index c849461..54a1dbf 100644
--- a/dubbo-filter/dubbo-filter-cache/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.cache.CacheFactory
+++ b/dubbo-filter/dubbo-filter-cache/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.cache.CacheFactory
@@ -1,4 +1,5 @@
threadlocal=org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory
lru=org.apache.dubbo.cache.support.lru.LruCacheFactory
jcache=org.apache.dubbo.cache.support.jcache.JCacheFactory
-expiring=org.apache.dubbo.cache.support.expiring.ExpiringCacheFactory
\ No newline at end of file
+expiring=org.apache.dubbo.cache.support.expiring.ExpiringCacheFactory
+lfu=org.apache.dubbo.cache.support.lfu.LfuCacheFactory
diff --git a/dubbo-filter/dubbo-filter-cache/src/test/java/org/apache/dubbo/cache/support/expiring/ExpiringCacheFactoryTest.java b/dubbo-filter/dubbo-filter-cache/src/test/java/org/apache/dubbo/cache/support/expiring/ExpiringCacheFactoryTest.java
index 23484c6..877faf4 100644
--- a/dubbo-filter/dubbo-filter-cache/src/test/java/org/apache/dubbo/cache/support/expiring/ExpiringCacheFactoryTest.java
+++ b/dubbo-filter/dubbo-filter-cache/src/test/java/org/apache/dubbo/cache/support/expiring/ExpiringCacheFactoryTest.java
@@ -19,18 +19,45 @@
import org.apache.dubbo.cache.Cache;
import org.apache.dubbo.cache.support.AbstractCacheFactory;
import org.apache.dubbo.cache.support.AbstractCacheFactoryTest;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.RpcInvocation;
import org.junit.jupiter.api.Test;
-import static org.hamcrest.core.Is.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
public class ExpiringCacheFactoryTest extends AbstractCacheFactoryTest {
@Test
- public void testLruCacheFactory() throws Exception {
+ public void testExpiringCacheFactory() throws Exception {
Cache cache = super.constructCache();
assertThat(cache instanceof ExpiringCache, is(true));
}
+ @Test
+ public void testExpiringCacheGetExpired() throws Exception {
+ URL url = URL.valueOf("test://test:12/test?cache=expiring&cache.seconds=1&cache.interval=1");
+ AbstractCacheFactory cacheFactory = getCacheFactory();
+ Invocation invocation = new RpcInvocation();
+ Cache cache = cacheFactory.getCache(url, invocation);
+ cache.put("testKey", "testValue");
+ Thread.sleep(2100);
+ assertNull(cache.get("testKey"));
+ }
+
+ @Test
+ public void testExpiringCacheUnExpired() throws Exception {
+ URL url = URL.valueOf("test://test:12/test?cache=expiring&cache.seconds=0&cache.interval=1");
+ AbstractCacheFactory cacheFactory = getCacheFactory();
+ Invocation invocation = new RpcInvocation();
+ Cache cache = cacheFactory.getCache(url, invocation);
+ cache.put("testKey", "testValue");
+ Thread.sleep(1100);
+ assertNotNull(cache.get("testKey"));
+ }
+
@Override
protected AbstractCacheFactory getCacheFactory() {
return new ExpiringCacheFactory();
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..13938ca 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
@@ -66,7 +66,7 @@
dynamicConfiguration.publishConfig(key, ServiceNameMapping.buildGroup(serviceInterface, group, version, protocol), content);
if (logger.isInfoEnabled()) {
logger.info(String.format("Dubbo service[%s] mapped to interface name[%s].",
- group, serviceInterface, group));
+ group, serviceInterface));
}
});
}
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 6fc6239..915b2cd 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
@@ -178,7 +178,7 @@
private String path; // most of the time, path is the same with the interface name.
private Map<String, String> params;
- // params configuried on consumer side,
+ // params configured on consumer side,
private transient Map<String, String> consumerParams;
// cached method params
private transient Map<String, Map<String, String>> methodParams;
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMethodMetadata.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMethodMetadata.java
index a675eb3..1531c97 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMethodMetadata.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMethodMetadata.java
@@ -159,8 +159,12 @@
@Override
public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof RestMethodMetadata)) return false;
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof RestMethodMetadata)) {
+ return false;
+ }
RestMethodMetadata that = (RestMethodMetadata) o;
return Objects.equals(getMethod(), that.getMethod()) &&
Objects.equals(getRequest(), that.getRequest()) &&
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadata.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadata.java
index 876b8a3..df396b0 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadata.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadata.java
@@ -76,8 +76,12 @@
@Override
public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof ServiceRestMetadata)) return false;
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof ServiceRestMetadata)) {
+ return false;
+ }
ServiceRestMetadata that = (ServiceRestMetadata) o;
return Objects.equals(getServiceInterface(), that.getServiceInterface()) &&
Objects.equals(getVersion(), that.getVersion()) &&
diff --git a/dubbo-metadata/dubbo-metadata-report-failover/pom.xml b/dubbo-metadata/dubbo-metadata-report-failover/pom.xml
new file mode 100644
index 0000000..18ed396
--- /dev/null
+++ b/dubbo-metadata/dubbo-metadata-report-failover/pom.xml
@@ -0,0 +1,38 @@
+<!--
+ 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/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>dubbo-metadata</artifactId>
+ <groupId>org.apache.dubbo</groupId>
+ <version>${revision}</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dubbo-metadata-report-failover</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-metadata-api</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/dubbo-metadata/dubbo-metadata-report-failover/src/main/java/org/apache/dubbo/metadata/store/failover/FailoverCondition.java b/dubbo-metadata/dubbo-metadata-report-failover/src/main/java/org/apache/dubbo/metadata/store/failover/FailoverCondition.java
new file mode 100644
index 0000000..512c34e
--- /dev/null
+++ b/dubbo-metadata/dubbo-metadata-report-failover/src/main/java/org/apache/dubbo/metadata/store/failover/FailoverCondition.java
@@ -0,0 +1,51 @@
+/*
+ * 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.metadata.store.failover;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.SPI;
+
+@SPI("failover")
+public interface FailoverCondition {
+
+ /**
+ * Whether metadata should be reported.
+ *
+ * @param url registry url, eg: zookeeper://127.0.0.1:2181
+ * @return true store metadata to the specified URL.
+ */
+ boolean shouldRegister(URL url);
+
+ /**
+ * Whether metadata should be read from specified url.
+ *
+ * @param url registry url, eg: zookeeper://127.0.0.1:2181
+ * @return true read metadata from specified URL.
+ */
+ boolean shouldQuery(URL url);
+
+ /**
+ * Judge whether it is a local region or a local datacenter.
+ * <p>
+ * Allows the local region or datacenter to be read first.
+ *
+ * @param url
+ * @return
+ */
+ boolean isLocalDataCenter(URL url);
+
+}
\ No newline at end of file
diff --git a/dubbo-metadata/dubbo-metadata-report-failover/src/main/java/org/apache/dubbo/metadata/store/failover/FailoverMetadataReport.java b/dubbo-metadata/dubbo-metadata-report-failover/src/main/java/org/apache/dubbo/metadata/store/failover/FailoverMetadataReport.java
new file mode 100644
index 0000000..e6a423d
--- /dev/null
+++ b/dubbo-metadata/dubbo-metadata-report-failover/src/main/java/org/apache/dubbo/metadata/store/failover/FailoverMetadataReport.java
@@ -0,0 +1,581 @@
+/*
+ * 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.metadata.store.failover;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.RemotingConstants;
+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.metadata.MappingListener;
+import org.apache.dubbo.metadata.MetadataInfo;
+import org.apache.dubbo.metadata.definition.model.ServiceDefinition;
+import org.apache.dubbo.metadata.report.MetadataReport;
+import org.apache.dubbo.metadata.report.MetadataReportFactory;
+import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;
+import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;
+import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
+import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_SPLIT_PATTERN;
+
+/**
+ * @author yiji@apache.org
+ */
+public class FailoverMetadataReport extends StrategyMetadataReport {
+
+ private static final Logger logger = LoggerFactory.getLogger(FailoverMetadataReport.class);
+
+ // proxy metadata report protocol, eg: zookeeper
+ private static final String PROTOCOL_KEY = "protocol";
+
+ private static final String CLUSTER_KEY = "clusters";
+
+ // A cluster may have multiple instances
+ private static final String HOST_KEY = "hosts";
+
+ private static final Pattern HOST_SPLIT_PATTERN = Pattern.compile("\\s*[|:]+\\s*");
+
+ // The metadata address of the agent.
+ private List<URL> failoverUrls;
+
+ // The metadata report instance.
+ private List<MetadataReportHolder> proxyReports;
+
+ // Local priority metadata center
+ private MetadataReportHolder localDataCenterReportHolder;
+
+ public FailoverMetadataReport(URL url) {
+ super(url);
+ this.failoverUrls = fetchBackupUrls();
+ this.proxyReports = buildProxyReports();
+ }
+
+ protected List<URL> fetchBackupUrls() {
+ String protocol = url.getParameter(PROTOCOL_KEY);
+ if (protocol == null || !ExtensionLoader.getExtensionLoader(MetadataReportFactory.class).hasExtension(protocol)) {
+ throw new IllegalArgumentException(
+ "No '" + protocol
+ + "' medata report extension found, please check if metadata report module dependencies are included.");
+ }
+
+ List<URL> urls = new ArrayList<>();
+
+ String clusters = this.url.getParameter(CLUSTER_KEY);
+ String backupHost = this.url.getParameter(HOST_KEY);
+ URL url = this.url.removeParameters(CLUSTER_KEY, HOST_KEY, PROTOCOL_KEY).setProtocol(protocol);
+
+ URL metadataURL = url;
+ if (backupHost != null && backupHost.length() > 0) {
+ metadataURL = metadataURL.addParameter(RemotingConstants.BACKUP_KEY, backupHost);
+ }
+ urls.add(metadataURL);
+
+ if (clusters != null && (clusters = clusters.trim()).length() > 0) {
+ String[] addresses = REGISTRY_SPLIT_PATTERN.split(clusters);
+ for (String address : addresses) {
+ /**
+ * find multiple cluster hosts, supports multiple
+ * metadata report center read and write operations.
+ */
+ String[] hosts = COMMA_SPLIT_PATTERN.split(address);
+ if (hosts.length > 0) {
+ String node = hosts[0];
+ // contains user name and password with address ?
+ String username = null, password = null;
+ int index = node.indexOf("@");
+ if (index > 0) {
+ String[] authority = HOST_SPLIT_PATTERN.split(node.substring(0, index));
+ username = authority[0];
+ password = authority[1];
+ node = node.substring(index + 1);
+ }
+
+ String[] hostInfo = HOST_SPLIT_PATTERN.split(node);
+ String host = hostInfo[0];
+ int port = Integer.parseInt(hostInfo[1]);
+ URL clusterURL = new URL(protocol, username, password, host, port, url.getPath(), url.getParameters());
+ /**
+ * append backup address if required,
+ * the same cluster may have more than one node.
+ */
+ if (hosts.length > 1) {
+ StringBuilder buffer = new StringBuilder();
+ for (int i = 1; i < hosts.length; i++) {
+ if (i > 1) {
+ buffer.append(",");
+ }
+ buffer.append(hosts[i]);
+ }
+ clusterURL = clusterURL.addParameters(RemotingConstants.BACKUP_KEY, buffer.toString());
+ }
+ urls.add(clusterURL);
+ }
+ }
+ }
+ return urls;
+ }
+
+ protected List<MetadataReportHolder> buildProxyReports() {
+ List<MetadataReportHolder> reports = new ArrayList<>();
+ if (this.failoverUrls != null && !this.failoverUrls.isEmpty()) {
+ ExtensionLoader<MetadataReportFactory> factoryLoader = ExtensionLoader.getExtensionLoader(MetadataReportFactory.class);
+ for (URL url : this.failoverUrls) {
+ try {
+ MetadataReportHolder holder = new MetadataReportHolder(url,
+ factoryLoader.getExtension(url.getProtocol()).getMetadataReport(url));
+ reports.add(holder);
+ } catch (Exception e) {
+ if (url.getParameter(CHECK_KEY, true)) {
+ throw new RuntimeException("Failed to create + '" + url.getProtocol() + "' metadata report extension instance", e);
+ }
+ if (logger.isWarnEnabled()) {
+ logger.warn("Failed to create + '" + url.getProtocol()
+ + "' metadata report extension instance, check=false found.");
+ }
+ }
+ }
+ }
+
+ Collections.shuffle(reports);
+
+ /**
+ * Select the local priority metadata cluster.
+ * In order to prevent clients from all connecting
+ * to the same cluster, random sorting has been done.
+ */
+ reports.forEach(holder -> {
+ if (isLocalDataCenter(holder.url)) {
+ this.localDataCenterReportHolder = holder;
+ }
+ });
+
+ return reports;
+ }
+
+ @Override
+ public void storeProviderMetadata(MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition) {
+ this.proxyReports.forEach((holder -> {
+ if (shouldRegister(holder.url)) {
+ try {
+ holder.report.storeProviderMetadata(providerMetadataIdentifier, serviceDefinition);
+ } catch (Exception e) {
+ if (url.getParameter(CHECK_KEY, true)) {
+ throw e;
+ }
+ }
+ } else {
+ if (logger.isInfoEnabled()) {
+ logger.info("Cancel to store provider metadata, register is false. url " + holder.url);
+ }
+ }
+ }));
+ }
+
+ @Override
+ public void storeConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, Map<String, String> serviceParameterMap) {
+ this.proxyReports.forEach(holder -> {
+ if (shouldRegister(holder.url)) {
+ try {
+ holder.report.storeConsumerMetadata(consumerMetadataIdentifier, serviceParameterMap);
+ } catch (Exception e) {
+ if (url.getParameter(CHECK_KEY, true)) {
+ throw e;
+ }
+ }
+ } else {
+ if (logger.isInfoEnabled()) {
+ logger.info("Cancel to store consumer metadata, register is false. url " + holder.url);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void publishAppMetadata(SubscriberMetadataIdentifier identifier, MetadataInfo metadataInfo) {
+ this.proxyReports.forEach(holder -> {
+ if (shouldRegister(holder.url)) {
+ try {
+ holder.report.publishAppMetadata(identifier, metadataInfo);
+ } catch (Exception e) {
+ if (url.getParameter(CHECK_KEY, true)) {
+ throw e;
+ }
+ }
+ } else {
+ if (logger.isInfoEnabled()) {
+ logger.info("Cancel to publish app metadata, register is false. url " + holder.url);
+ }
+ }
+ });
+ }
+
+ @Override
+ public String getServiceDefinition(MetadataIdentifier metadataIdentifier) {
+ /**
+ * Support local region or datacenter to read first,
+ * If current region or datacenter failed, it will be demoted to another region or datacenter.
+ */
+ MetadataReportHolder localReportHolder = this.localDataCenterReportHolder;
+ if (localReportHolder != null && shouldQuery(localReportHolder.url)) {
+ try {
+ String definition = localReportHolder.report.getServiceDefinition(metadataIdentifier);
+ if (definition != null && definition.length() > 0) {
+ return definition;
+ }
+ } catch (Exception e) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Failed to get service definition from local metadata report center, url " + localReportHolder.url);
+ }
+ }
+ }
+
+ for (MetadataReportHolder holder : proxyReports) {
+ /**
+ * Skip the local region or datacenter read,
+ * which was queried already.
+ */
+ if (localReportHolder != null
+ && holder.url == localReportHolder.url) {
+ continue;
+ }
+
+ if (shouldQuery(holder.url)) {
+ try {
+ String definition = holder.report.getServiceDefinition(metadataIdentifier);
+ if (definition != null && definition.length() > 0) {
+ return definition;
+ }
+ } catch (Exception e) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Failed to get service definition from metadata report center, url " + holder.url);
+ }
+ }
+ }
+
+ // should never happened.
+ if (logger.isInfoEnabled()) {
+ logger.info("Cancel to get service definition, should query is false. url " + holder.url);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public MetadataInfo getAppMetadata(SubscriberMetadataIdentifier identifier, Map<String, String> instanceMetadata) {
+ /**
+ * Support local region or datacenter to read first,
+ * If current region or datacenter failed, it will be demoted to another region or datacenter.
+ */
+ MetadataReportHolder localReportHolder = this.localDataCenterReportHolder;
+ if (localReportHolder != null && shouldQuery(localReportHolder.url)) {
+ try {
+ MetadataInfo metadataInfo = localReportHolder.report.getAppMetadata(identifier, instanceMetadata);
+ if (metadataInfo != null) {
+ return metadataInfo;
+ }
+ } catch (Exception e) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Failed to get app metadata from local metadata report center, url " + localReportHolder.url);
+ }
+ }
+ }
+
+ for (MetadataReportHolder holder : proxyReports) {
+ /**
+ * Skip the local region or datacenter read,
+ * which was queried already.
+ */
+ if (localReportHolder != null
+ && holder.url == localReportHolder.url) {
+ continue;
+ }
+
+ if (shouldQuery(holder.url)) {
+ try {
+ MetadataInfo metadataInfo = holder.report.getAppMetadata(identifier, instanceMetadata);
+ if (metadataInfo != null) {
+ return metadataInfo;
+ }
+ } catch (Exception e) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Failed to get app metadata from metadata report center, url " + holder.url);
+ }
+ }
+ }
+
+ // should never happened.
+ if (logger.isInfoEnabled()) {
+ logger.info("Cancel to get app metadata, should query is false. url " + holder.url);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public Set<String> getServiceAppMapping(String serviceKey, MappingListener listener, URL url) {
+ /**
+ * Support local region or datacenter to read first,
+ * If current region or datacenter failed, it will be demoted to another region or datacenter.
+ */
+ MetadataReportHolder localReportHolder = this.localDataCenterReportHolder;
+ if (localReportHolder != null && shouldQuery(localReportHolder.url)) {
+ try {
+ Set<String> appMapping = localReportHolder.report.getServiceAppMapping(serviceKey, listener, url);
+ if (appMapping != null && !appMapping.isEmpty()) {
+ return appMapping;
+ }
+ } catch (Exception e) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Failed to get service mapping from local metadata report center, url " + localReportHolder.url);
+ }
+ }
+ }
+
+ for (MetadataReportHolder holder : proxyReports) {
+ /**
+ * Skip the local region or datacenter read,
+ * which was queried already.
+ */
+ if (localReportHolder != null
+ && holder.url == localReportHolder.url) {
+ continue;
+ }
+
+ if (shouldQuery(holder.url)) {
+ try {
+ Set<String> appMapping = holder.report.getServiceAppMapping(serviceKey, listener, url);
+ if (appMapping != null && !appMapping.isEmpty()) {
+ return appMapping;
+ }
+ } catch (Exception e) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Failed to get service mapping from metadata report center, url " + holder.url);
+ }
+ }
+ }
+
+ // should never happened.
+ if (logger.isInfoEnabled()) {
+ logger.info("Cancel to get service mapping, should query is false. url " + holder.url);
+ }
+ }
+
+ return Collections.EMPTY_SET;
+ }
+
+ @Override
+ public void registerServiceAppMapping(String serviceKey, String application, URL url) {
+ this.proxyReports.forEach(holder -> {
+ if (shouldRegister(holder.url)) {
+ try {
+ holder.report.registerServiceAppMapping(serviceKey, application, url);
+ } catch (Exception e) {
+ if (url.getParameter(CHECK_KEY, true)) {
+ throw e;
+ }
+ }
+ } else {
+ if (logger.isInfoEnabled()) {
+ logger.info("Cancel to register service app mapping, register is false. url " + holder.url);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void saveServiceMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url) {
+ this.proxyReports.forEach(holder -> {
+ if (shouldRegister(holder.url)) {
+ try {
+ holder.report.saveServiceMetadata(metadataIdentifier, url);
+ } catch (Exception e) {
+ if (url.getParameter(CHECK_KEY, true)) {
+ throw e;
+ }
+ }
+ } else {
+ if (logger.isInfoEnabled()) {
+ logger.info("Cancel to register service app mapping, register is false. url " + holder.url);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void saveSubscribedData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, Set<String> urls) {
+ this.proxyReports.forEach(holder -> {
+ if (shouldRegister(holder.url)) {
+ try {
+ holder.report.saveSubscribedData(subscriberMetadataIdentifier, urls);
+ } catch (Exception e) {
+ if (url.getParameter(CHECK_KEY, true)) {
+ throw e;
+ }
+ }
+ } else {
+ if (logger.isInfoEnabled()) {
+ logger.info("Cancel to register service app mapping, register is false. url " + holder.url);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void removeServiceMetadata(ServiceMetadataIdentifier metadataIdentifier) {
+ this.proxyReports.forEach(holder -> {
+ if (shouldRegister(holder.url)) {
+ try {
+ holder.report.removeServiceMetadata(metadataIdentifier);
+ } catch (Exception e) {
+ if (url.getParameter(CHECK_KEY, true)) {
+ throw e;
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public List<String> getExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {
+ /**
+ * Support local region or datacenter to read first,
+ * If current region or datacenter failed, it will be demoted to another region or datacenter.
+ */
+ MetadataReportHolder localReportHolder = this.localDataCenterReportHolder;
+ if (localReportHolder != null && shouldQuery(localReportHolder.url)) {
+ try {
+ List<String> exportedURLs = localReportHolder.report.getExportedURLs(metadataIdentifier);
+ if (exportedURLs != null && !exportedURLs.isEmpty()) {
+ return exportedURLs;
+ }
+ } catch (Exception e) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Failed to get exported urls from local metadata report center, url " + localReportHolder.url);
+ }
+ }
+ }
+
+ for (MetadataReportHolder holder : proxyReports) {
+ /**
+ * Skip the local region or datacenter read,
+ * which was queried already.
+ */
+ if (localReportHolder != null
+ && holder.url == localReportHolder.url) {
+ continue;
+ }
+
+ if (shouldQuery(holder.url)) {
+ try {
+ List<String> exportedURLs = holder.report.getExportedURLs(metadataIdentifier);
+ if (exportedURLs != null && !exportedURLs.isEmpty()) {
+ return exportedURLs;
+ }
+ } catch (Exception e) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Failed to get exported urls from metadata report center, url " + holder.url);
+ }
+ }
+ }
+
+ // should never happened.
+ if (logger.isInfoEnabled()) {
+ logger.info("Cancel to get exported urls, should query is false. url " + holder.url);
+ }
+ }
+
+ return Collections.EMPTY_LIST;
+ }
+
+ @Override
+ public List<String> getSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) {
+ /**
+ * Support local region or datacenter to read first,
+ * If current region or datacenter failed, it will be demoted to another region or datacenter.
+ */
+ MetadataReportHolder localReportHolder = this.localDataCenterReportHolder;
+ if (localReportHolder != null && shouldQuery(localReportHolder.url)) {
+ try {
+ List<String> subscribedURLs = localReportHolder.report.getSubscribedURLs(subscriberMetadataIdentifier);
+ if (subscribedURLs != null && !subscribedURLs.isEmpty()) {
+ return subscribedURLs;
+ }
+ } catch (Exception e) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Failed to get subscribed urls from local metadata report center, url " + localReportHolder.url);
+ }
+ }
+ }
+
+ for (MetadataReportHolder holder : proxyReports) {
+ /**
+ * Skip the local region or datacenter read,
+ * which was queried already.
+ */
+ if (localReportHolder != null
+ && holder.url == localReportHolder.url) {
+ continue;
+ }
+
+ if (shouldQuery(holder.url)) {
+ try {
+ List<String> subscribedURLs = holder.report.getSubscribedURLs(subscriberMetadataIdentifier);
+ if (subscribedURLs != null && !subscribedURLs.isEmpty()) {
+ return subscribedURLs;
+ }
+ } catch (Exception e) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Failed to get subscribed urls from metadata report center, url " + holder.url);
+ }
+ }
+ }
+
+ // should never happened.
+ if (logger.isInfoEnabled()) {
+ logger.info("Cancel to get subscribed urls, should query is false. url " + holder.url);
+ }
+ }
+
+ return Collections.EMPTY_LIST;
+ }
+
+ public List<MetadataReportHolder> getProxyReports() {
+ return proxyReports;
+ }
+
+ class MetadataReportHolder {
+
+ final URL url;
+ final MetadataReport report;
+
+ public MetadataReportHolder(URL url, MetadataReport report) {
+ this.url = url;
+ this.report = report;
+ }
+ }
+}
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java b/dubbo-metadata/dubbo-metadata-report-failover/src/main/java/org/apache/dubbo/metadata/store/failover/FailoverMetadataReportFactory.java
similarity index 69%
copy from dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java
copy to dubbo-metadata/dubbo-metadata-report-failover/src/main/java/org/apache/dubbo/metadata/store/failover/FailoverMetadataReportFactory.java
index 7bef1f5..b47c14c 100644
--- a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java
+++ b/dubbo-metadata/dubbo-metadata-report-failover/src/main/java/org/apache/dubbo/metadata/store/failover/FailoverMetadataReportFactory.java
@@ -14,15 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.registry.multicast;
+package org.apache.dubbo.metadata.store.failover;
import org.apache.dubbo.common.URL;
-import org.apache.dubbo.registry.client.ServiceDiscovery;
-import org.apache.dubbo.registry.client.ServiceDiscoveryFactory;
+import org.apache.dubbo.metadata.report.MetadataReport;
+import org.apache.dubbo.metadata.report.support.AbstractMetadataReportFactory;
-public class MulticastServiceDiscoveryFactory implements ServiceDiscoveryFactory {
+public class FailoverMetadataReportFactory extends AbstractMetadataReportFactory {
+
@Override
- public ServiceDiscovery getServiceDiscovery(URL registryURL) {
- return new MulticastServiceDiscovery();
+ protected MetadataReport createMetadataReport(URL url) {
+ return new FailoverMetadataReport(url);
}
-}
+}
\ No newline at end of file
diff --git a/dubbo-metadata/dubbo-metadata-report-failover/src/main/java/org/apache/dubbo/metadata/store/failover/StrategyMetadataReport.java b/dubbo-metadata/dubbo-metadata-report-failover/src/main/java/org/apache/dubbo/metadata/store/failover/StrategyMetadataReport.java
new file mode 100644
index 0000000..ef7636c
--- /dev/null
+++ b/dubbo-metadata/dubbo-metadata-report-failover/src/main/java/org/apache/dubbo/metadata/store/failover/StrategyMetadataReport.java
@@ -0,0 +1,88 @@
+/*
+ * 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.metadata.store.failover;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.metadata.report.MetadataReport;
+
+/**
+ * @author yiji@apache.org
+ */
+public abstract class StrategyMetadataReport implements MetadataReport {
+
+ // failover configured url, eg: failover://127.0.1:2181?backup=localhost:2181|localhost:2181
+ protected URL url;
+
+ protected static final String STRATEGY_KEY = "strategy";
+
+ // proxy metadata report strategy, used to decide whether to write or read metadata
+ protected FailoverCondition strategy;
+
+ protected ExtensionLoader<FailoverCondition> failoverLoader = ExtensionLoader.getExtensionLoader(FailoverCondition.class);
+
+ public StrategyMetadataReport(URL url) {
+ if (url == null) {
+ throw new IllegalArgumentException("url is required.");
+ }
+ this.url = url;
+ createFailoverStrategy(url);
+ }
+
+ protected void createFailoverStrategy(URL url) {
+ String strategy = url.getParameter(STRATEGY_KEY);
+ if (strategy != null) {
+ if (!failoverLoader.hasExtension(strategy)) {
+ throw new IllegalArgumentException("No '" + strategy + "' failover condition extension found.");
+ }
+ this.strategy = failoverLoader.getExtension(strategy);
+ }
+ }
+
+ /**
+ * Whether metadata should be reported.
+ *
+ * @param url registry url, eg: zookeeper://127.0.0.1:2181
+ * @return true store metadata to the specified URL.
+ */
+ protected boolean shouldRegister(URL url) {
+ return this.strategy == null || this.strategy.shouldRegister(url);
+ }
+
+ /**
+ * Whether metadata should be read from specified url.
+ *
+ * @param url registry url, eg: zookeeper://127.0.0.1:2181
+ * @return true read metadata from specified URL.
+ */
+ protected boolean shouldQuery(URL url) {
+ return this.strategy == null || this.strategy.shouldQuery(url);
+ }
+
+ /**
+ * Judge whether it is a local region or a local datacenter.
+ * <p>
+ * Allows the local region or datacenter to be read first.
+ *
+ * @param url
+ * @return
+ */
+ protected boolean isLocalDataCenter(URL url) {
+ return this.strategy == null || this.strategy.isLocalDataCenter(url);
+ }
+
+}
\ No newline at end of file
diff --git a/dubbo-metadata/dubbo-metadata-report-failover/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory b/dubbo-metadata/dubbo-metadata-report-failover/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory
new file mode 100644
index 0000000..e530c5e
--- /dev/null
+++ b/dubbo-metadata/dubbo-metadata-report-failover/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory
@@ -0,0 +1 @@
+failover=org.apache.dubbo.metadata.store.failover.FailoverMetadataReportFactory
diff --git a/dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/FailoverMetadataReportTest.java b/dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/FailoverMetadataReportTest.java
new file mode 100644
index 0000000..c7e50a8
--- /dev/null
+++ b/dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/FailoverMetadataReportTest.java
@@ -0,0 +1,222 @@
+/*
+ * 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.metadata.store.failover;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.metadata.MetadataInfo;
+import org.apache.dubbo.metadata.definition.model.ServiceDefinition;
+import org.apache.dubbo.metadata.report.MetadataReport;
+import org.apache.dubbo.metadata.report.MetadataReportFactory;
+import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;
+import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;
+import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;
+import org.apache.dubbo.metadata.report.support.AbstractMetadataReportFactory;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+public class FailoverMetadataReportTest {
+
+ private ExtensionLoader<MetadataReportFactory> reportLoader = ExtensionLoader.getExtensionLoader(MetadataReportFactory.class);
+
+ private URL mockURL = URL.valueOf("failover://127.0.0.1:2181?clusters=localhost:3181&protocol=mock");
+
+ @AfterEach
+ void tearDown() {
+ clearFailoverReport();
+ clearFailoverFactory();
+ }
+
+ @Test
+ public void testReadWriteAllMetadataReport() {
+ URL url = mockURL.addParameter("strategy", "all");
+ FailoverMetadataReport report = getFailoverReport(url);
+ Assertions.assertNotNull(report.getProxyReports(), "metadata reports should not be null.");
+ Assertions.assertEquals(2, report.getProxyReports().size(),
+ "expect 2 metadata report, actual " + report.getProxyReports().size());
+
+ MetadataIdentifier identifier = new MetadataIdentifier("helloService", null, null, null, "test");
+ ServiceDefinition definition = new ServiceDefinition();
+ definition.setCanonicalName("helloService");
+ report.storeProviderMetadata(identifier, definition);
+ Assertions.assertNotNull(report.getServiceDefinition(identifier));
+ // assert all metadata report write already.
+ for (FailoverMetadataReport.MetadataReportHolder holder : report.getProxyReports()) {
+ Assertions.assertNotNull(holder.report.getServiceDefinition(identifier));
+ }
+
+ HashMap parameterMap = new HashMap();
+ report.storeConsumerMetadata(identifier, parameterMap);
+ // assert all metadata report write already.
+ for (FailoverMetadataReport.MetadataReportHolder holder : report.getProxyReports()) {
+ Assertions.assertEquals(parameterMap, ((MockMetadataReport) holder.report).consumerMetadata.get(identifier));
+ }
+
+ SubscriberMetadataIdentifier subscribeIdentifier = new SubscriberMetadataIdentifier("test", "1.0");
+ MetadataInfo metadataInfo = new MetadataInfo(subscribeIdentifier.getApplication(), subscribeIdentifier.getRevision(), null);
+ report.publishAppMetadata(subscribeIdentifier, metadataInfo);
+ Assertions.assertEquals(metadataInfo, report.getAppMetadata(subscribeIdentifier, null));
+ // assert all metadata report write already.
+ for (FailoverMetadataReport.MetadataReportHolder holder : report.getProxyReports()) {
+ Assertions.assertEquals(metadataInfo, holder.report.getAppMetadata(subscribeIdentifier, null));
+ }
+
+ report.registerServiceAppMapping("helloService", "test", null);
+ Set<String> appNames = report.getServiceAppMapping("helloService", null, null);
+ Assertions.assertEquals(appNames, report.getServiceAppMapping("helloService", null, null));
+ // assert all metadata report write already.
+ for (FailoverMetadataReport.MetadataReportHolder holder : report.getProxyReports()) {
+ Assertions.assertEquals(appNames, holder.report.getServiceAppMapping("helloService", null, null));
+ }
+
+ ServiceMetadataIdentifier serviceIdentifier = new ServiceMetadataIdentifier("helloService", null, null, null, "1.0", "dubbo");
+ report.saveServiceMetadata(serviceIdentifier, url);
+ Assertions.assertNotNull(report.getExportedURLs(serviceIdentifier));
+ // assert all metadata report write already.
+ for (FailoverMetadataReport.MetadataReportHolder holder : report.getProxyReports()) {
+ Assertions.assertNotNull(holder.report.getExportedURLs(serviceIdentifier));
+ }
+
+ report.saveSubscribedData(subscribeIdentifier, new HashSet<>());
+ Assertions.assertNotNull(report.getSubscribedURLs(subscribeIdentifier));
+ // assert all metadata report write already.
+ for (FailoverMetadataReport.MetadataReportHolder holder : report.getProxyReports()) {
+ Assertions.assertNotNull(holder.report.getSubscribedURLs(subscribeIdentifier));
+ }
+ }
+
+ @Test
+ public void testLocalDataCenterMetadataReport() {
+ URL url = mockURL.addParameter("strategy", "local");
+ FailoverMetadataReport report = getFailoverReport(url);
+ Assertions.assertNotNull(report.getProxyReports(), "metadata reports should not be null.");
+ Assertions.assertEquals(2, report.getProxyReports().size(),
+ "expect 2 metadata report, actual " + report.getProxyReports().size());
+
+ MetadataReport localReport = null, failoverReport = null;
+ for (FailoverMetadataReport.MetadataReportHolder holder : report.getProxyReports()) {
+ if (holder.url.getBackupAddress().contains(url.getAddress())) {
+ localReport = holder.report;
+ } else {
+ failoverReport = holder.report;
+ }
+ }
+ Assertions.assertNotNull(localReport);
+ Assertions.assertNotNull(failoverReport);
+
+ MetadataIdentifier identifier = new MetadataIdentifier("helloService", null, null, null, "test");
+ ServiceDefinition definition = new ServiceDefinition();
+ definition.setCanonicalName("helloService");
+ report.storeProviderMetadata(identifier, definition);
+
+ // assert local metadata report write already.
+ Assertions.assertNotNull(report.getServiceDefinition(identifier));
+ Assertions.assertNotNull(localReport.getServiceDefinition(identifier));
+ Assertions.assertNull(failoverReport.getServiceDefinition(identifier));
+
+ HashMap parameterMap = new HashMap();
+ report.storeConsumerMetadata(identifier, parameterMap);
+ // assert local metadata report write already.
+ Assertions.assertEquals(parameterMap, ((MockMetadataReport) localReport).consumerMetadata.get(identifier));
+ Assertions.assertNotEquals(parameterMap, ((MockMetadataReport) failoverReport).consumerMetadata.get(identifier));
+
+ SubscriberMetadataIdentifier subscribeIdentifier = new SubscriberMetadataIdentifier("test", "1.0");
+ MetadataInfo metadataInfo = new MetadataInfo(subscribeIdentifier.getApplication(), subscribeIdentifier.getRevision(), null);
+ report.publishAppMetadata(subscribeIdentifier, metadataInfo);
+ // assert all metadata report write already.
+ Assertions.assertEquals(metadataInfo, report.getAppMetadata(subscribeIdentifier, null));
+ Assertions.assertEquals(metadataInfo, localReport.getAppMetadata(subscribeIdentifier, null));
+ Assertions.assertNotEquals(metadataInfo, failoverReport.getAppMetadata(subscribeIdentifier, null));
+
+ report.registerServiceAppMapping("helloService", "test", null);
+ Set<String> appNames = report.getServiceAppMapping("helloService", null, null);
+
+ // assert local metadata report write already.
+ Assertions.assertEquals(appNames, report.getServiceAppMapping("helloService", null, null));
+ Assertions.assertEquals(appNames, localReport.getServiceAppMapping("helloService", null, null));
+ Assertions.assertNotEquals(appNames, failoverReport.getServiceAppMapping("helloService", null, null));
+
+ ServiceMetadataIdentifier serviceIdentifier = new ServiceMetadataIdentifier("helloService", null, null, null, "1.0", "dubbo");
+ report.saveServiceMetadata(serviceIdentifier, url);
+ // assert local metadata report write already.
+ Assertions.assertNotNull(report.getExportedURLs(serviceIdentifier));
+ Assertions.assertNotNull(localReport.getExportedURLs(serviceIdentifier));
+ Assertions.assertNull(failoverReport.getExportedURLs(serviceIdentifier));
+
+ Set<String> urls = new HashSet<>();
+ urls.add(url.toFullString());
+ report.saveSubscribedData(subscribeIdentifier, urls);
+ // assert local metadata report write already.
+ Assertions.assertEquals(new ArrayList<>(urls), report.getSubscribedURLs(subscribeIdentifier));
+ Assertions.assertEquals(new ArrayList<>(urls), localReport.getSubscribedURLs(subscribeIdentifier));
+ Assertions.assertNotEquals(new ArrayList<>(urls), failoverReport.getSubscribedURLs(subscribeIdentifier));
+ }
+
+ protected FailoverMetadataReport getFailoverReport(URL url) {
+ MetadataReportFactory reportFactory = reportLoader.getExtension(url.getProtocol());
+ Assertions.assertTrue(reportFactory instanceof FailoverMetadataReportFactory,
+ "expect " + FailoverMetadataReportFactory.class.getName() + " instance type, "
+ + "actual " + reportFactory.getClass().getName() + " instance type");
+
+ MetadataReport report = reportFactory.getMetadataReport(url);
+ Assertions.assertTrue(report instanceof FailoverMetadataReport,
+ "expect " + FailoverMetadataReport.class.getName() + " instance type, "
+ + "actual " + report.getClass().getName() + " instance type");
+
+ FailoverMetadataReport failover = (FailoverMetadataReport) report;
+ return failover;
+ }
+
+ private void clearFailoverReport() {
+ FailoverMetadataReport report = getFailoverReport(mockURL);
+ for (FailoverMetadataReport.MetadataReportHolder holder : report.getProxyReports()) {
+ if (holder.report instanceof MockMetadataReport) {
+ ((MockMetadataReport) (holder.report)).reset();
+ }
+ }
+ }
+
+ private void clearFailoverFactory() {
+ MetadataReportFactory factory = reportLoader.getExtension(mockURL.getProtocol());
+ try {
+ Field reportCache = AbstractMetadataReportFactory.class.getDeclaredField("SERVICE_STORE_MAP");
+ if (!reportCache.isAccessible()) {
+ reportCache.setAccessible(true);
+ }
+ Map<String, MetadataReport> serviceStore = (Map<String, MetadataReport>) reportCache.get(factory);
+ if (serviceStore != null) {
+ for (Iterator<Map.Entry<String, MetadataReport>> iterator = serviceStore.entrySet().iterator(); iterator.hasNext(); ) {
+ Map.Entry<String, MetadataReport> entry = iterator.next();
+ if (entry.getKey().startsWith(mockURL.getProtocol())) {
+ iterator.remove();
+ }
+ }
+ }
+ } catch (NoSuchFieldException | IllegalAccessException ignored) {
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java b/dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/MockAllFailoverCondition.java
similarity index 69%
copy from dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java
copy to dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/MockAllFailoverCondition.java
index 7bef1f5..1aa0e7c 100644
--- a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java
+++ b/dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/MockAllFailoverCondition.java
@@ -14,15 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.registry.multicast;
+package org.apache.dubbo.metadata.store.failover;
import org.apache.dubbo.common.URL;
-import org.apache.dubbo.registry.client.ServiceDiscovery;
-import org.apache.dubbo.registry.client.ServiceDiscoveryFactory;
-public class MulticastServiceDiscoveryFactory implements ServiceDiscoveryFactory {
+public class MockAllFailoverCondition extends MockLocalFailoverCondition {
+
@Override
- public ServiceDiscovery getServiceDiscovery(URL registryURL) {
- return new MulticastServiceDiscovery();
+ public boolean shouldRegister(URL url) {
+ return true;
}
-}
+
+ @Override
+ public boolean isLocalDataCenter(URL url) {
+ // we don't care about local datacenter first.
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/MockLocalFailoverCondition.java b/dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/MockLocalFailoverCondition.java
new file mode 100644
index 0000000..1efa1ac
--- /dev/null
+++ b/dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/MockLocalFailoverCondition.java
@@ -0,0 +1,45 @@
+/*
+ * 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.metadata.store.failover;
+
+import org.apache.dubbo.common.URL;
+
+/**
+ * @author yiji@apache.org
+ */
+public class MockLocalFailoverCondition implements FailoverCondition {
+
+ @Override
+ public boolean shouldRegister(URL url) {
+ // we just register same datacenter.
+ return isLocalDataCenter(url);
+ }
+
+ @Override
+ public boolean shouldQuery(URL url) {
+ // we want read any metadata report server.
+ return true;
+ }
+
+ @Override
+ public boolean isLocalDataCenter(URL url) {
+ // we mock current datacenter is `127.0.0.1:2181`
+ String current = "127.0.0.1:2181";
+ return url.getBackupAddress().contains(current);
+ }
+
+}
\ No newline at end of file
diff --git a/dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/MockMetadataReport.java b/dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/MockMetadataReport.java
new file mode 100644
index 0000000..a264812
--- /dev/null
+++ b/dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/MockMetadataReport.java
@@ -0,0 +1,131 @@
+/*
+ * 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.metadata.store.failover;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.ConcurrentHashSet;
+import org.apache.dubbo.metadata.MappingListener;
+import org.apache.dubbo.metadata.MetadataInfo;
+import org.apache.dubbo.metadata.definition.model.ServiceDefinition;
+import org.apache.dubbo.metadata.report.MetadataReport;
+import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;
+import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;
+import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+public class MockMetadataReport implements MetadataReport {
+
+ public URL url;
+
+ public ConcurrentMap<MetadataIdentifier, ServiceDefinition> providerMetadata = new ConcurrentHashMap<>();
+ public ConcurrentMap<SubscriberMetadataIdentifier, MetadataInfo> appMetadata = new ConcurrentHashMap<>();
+ public ConcurrentMap<String, Set<String>> appMapping = new ConcurrentHashMap<>();
+ public ConcurrentMap<MetadataIdentifier, Map<String, String>> consumerMetadata = new ConcurrentHashMap<>();
+ public ConcurrentMap<ServiceMetadataIdentifier, List<String>> serviceMetadata = new ConcurrentHashMap<>();
+ public ConcurrentMap<SubscriberMetadataIdentifier, Set<String>> subscribeMetadata = new ConcurrentHashMap<>();
+
+ public MockMetadataReport(URL url) {
+ this.url = url;
+ }
+
+ @Override
+ public void storeProviderMetadata(MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition) {
+ providerMetadata.put(providerMetadataIdentifier, serviceDefinition);
+ }
+
+ @Override
+ public String getServiceDefinition(MetadataIdentifier metadataIdentifier) {
+ ServiceDefinition definition = providerMetadata.get(metadataIdentifier);
+ return definition == null ? null : definition.toString();
+ }
+
+ @Override
+ public void publishAppMetadata(SubscriberMetadataIdentifier identifier, MetadataInfo metadataInfo) {
+ appMetadata.put(identifier, metadataInfo);
+ }
+
+ @Override
+ public MetadataInfo getAppMetadata(SubscriberMetadataIdentifier identifier, Map<String, String> instanceMetadata) {
+ return appMetadata.get(identifier);
+ }
+
+ @Override
+ public Set<String> getServiceAppMapping(String serviceKey, MappingListener listener, URL url) {
+ return appMapping.get(serviceKey);
+ }
+
+ @Override
+ public void registerServiceAppMapping(String serviceKey, String application, URL url) {
+ appMapping.putIfAbsent(serviceKey, new ConcurrentHashSet<>());
+ Set<String> appNames = appMapping.get(serviceKey);
+ appNames.add(application);
+ }
+
+ @Override
+ public void storeConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, Map<String, String> serviceParameterMap) {
+ consumerMetadata.put(consumerMetadataIdentifier, serviceParameterMap);
+ }
+
+ @Override
+ public List<String> getExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {
+ return serviceMetadata.get(metadataIdentifier);
+ }
+
+ @Override
+ public void saveServiceMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url) {
+ serviceMetadata.putIfAbsent(metadataIdentifier, new CopyOnWriteArrayList<>());
+ List<String> urls = serviceMetadata.get(metadataIdentifier);
+ urls.add(url.toFullString());
+ }
+
+ @Override
+ public void removeServiceMetadata(ServiceMetadataIdentifier metadataIdentifier) {
+ serviceMetadata.remove(metadataIdentifier);
+ }
+
+ @Override
+ public void saveSubscribedData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, Set<String> urls) {
+ subscribeMetadata.putIfAbsent(subscriberMetadataIdentifier, new CopyOnWriteArraySet());
+ Set<String> metadataUrls = subscribeMetadata.get(subscriberMetadataIdentifier);
+ metadataUrls.addAll(urls);
+ }
+
+ @Override
+ public List<String> getSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) {
+ Set<String> urls = subscribeMetadata.get(subscriberMetadataIdentifier);
+ if (urls == null) { return Collections.EMPTY_LIST; }
+ return new ArrayList<>(urls);
+ }
+
+ public void reset() {
+ providerMetadata.clear();
+ appMetadata.clear();
+ appMapping.clear();
+ consumerMetadata.clear();
+ serviceMetadata.clear();
+ subscribeMetadata.clear();
+ }
+}
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java b/dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/MockMetadataReportFactory.java
similarity index 69%
copy from dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java
copy to dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/MockMetadataReportFactory.java
index 7bef1f5..0c1c73e 100644
--- a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java
+++ b/dubbo-metadata/dubbo-metadata-report-failover/src/test/java/org/apache/dubbo/metadata/store/failover/MockMetadataReportFactory.java
@@ -14,15 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.registry.multicast;
+package org.apache.dubbo.metadata.store.failover;
import org.apache.dubbo.common.URL;
-import org.apache.dubbo.registry.client.ServiceDiscovery;
-import org.apache.dubbo.registry.client.ServiceDiscoveryFactory;
+import org.apache.dubbo.metadata.report.MetadataReport;
+import org.apache.dubbo.metadata.report.support.AbstractMetadataReportFactory;
-public class MulticastServiceDiscoveryFactory implements ServiceDiscoveryFactory {
+public class MockMetadataReportFactory extends AbstractMetadataReportFactory {
+
@Override
- public ServiceDiscovery getServiceDiscovery(URL registryURL) {
- return new MulticastServiceDiscovery();
+ protected MetadataReport createMetadataReport(URL url) {
+ return new MockMetadataReport(url);
}
-}
+
+}
\ No newline at end of file
diff --git a/dubbo-metadata/dubbo-metadata-report-failover/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory b/dubbo-metadata/dubbo-metadata-report-failover/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory
new file mode 100644
index 0000000..3336979
--- /dev/null
+++ b/dubbo-metadata/dubbo-metadata-report-failover/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory
@@ -0,0 +1 @@
+mock=org.apache.dubbo.metadata.store.failover.MockMetadataReportFactory
\ No newline at end of file
diff --git a/dubbo-metadata/dubbo-metadata-report-failover/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.store.failover.FailoverCondition b/dubbo-metadata/dubbo-metadata-report-failover/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.store.failover.FailoverCondition
new file mode 100644
index 0000000..ee09f7c
--- /dev/null
+++ b/dubbo-metadata/dubbo-metadata-report-failover/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.store.failover.FailoverCondition
@@ -0,0 +1,2 @@
+local=org.apache.dubbo.metadata.store.failover.MockLocalFailoverCondition
+all=org.apache.dubbo.metadata.store.failover.MockAllFailoverCondition
\ No newline at end of file
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 b221a5b..aea0ebb 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
@@ -20,6 +20,7 @@
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;
@@ -162,22 +163,30 @@
public Set<String> getServiceAppMapping(String serviceKey, MappingListener listener, URL url) {
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-metadata/pom.xml b/dubbo-metadata/pom.xml
index 17ceada..e72db49 100644
--- a/dubbo-metadata/pom.xml
+++ b/dubbo-metadata/pom.xml
@@ -31,6 +31,7 @@
<module>dubbo-metadata-api</module>
<module>dubbo-metadata-definition-protobuf</module>
<module>dubbo-metadata-report-zookeeper</module>
+ <module>dubbo-metadata-report-failover</module>
<module>dubbo-metadata-report-redis</module>
<module>dubbo-metadata-report-consul</module>
<module>dubbo-metadata-report-etcd</module>
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..4f33ec6 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
@@ -56,6 +56,7 @@
private static final Logger logger = LoggerFactory.getLogger(MonitorFilter.class);
private static final String MONITOR_FILTER_START_TIME = "monitor_filter_start_time";
+ private static final String MONITOR_REMOTE_HOST_STORE = "monitor_remote_host_store";
/**
* The Concurrent counter
@@ -84,6 +85,7 @@
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
if (invoker.getUrl().hasParameter(MONITOR_KEY)) {
invocation.put(MONITOR_FILTER_START_TIME, System.currentTimeMillis());
+ invocation.put(MONITOR_REMOTE_HOST_STORE, RpcContext.getContext().getRemoteHost());
getConcurrent(invoker, invocation).incrementAndGet(); // count up
}
return invoker.invoke(invocation); // proceed invocation chain
@@ -98,7 +100,7 @@
@Override
public void onResponse(Result result, Invoker<?> invoker, Invocation invocation) {
if (invoker.getUrl().hasParameter(MONITOR_KEY)) {
- collect(invoker, invocation, result, RpcContext.getContext().getRemoteHost(), (long) invocation.get(MONITOR_FILTER_START_TIME), false);
+ collect(invoker, invocation, result, (String) invocation.get(MONITOR_REMOTE_HOST_STORE), (long) invocation.get(MONITOR_FILTER_START_TIME), false);
getConcurrent(invoker, invocation).decrementAndGet(); // count down
}
}
@@ -106,7 +108,7 @@
@Override
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
if (invoker.getUrl().hasParameter(MONITOR_KEY)) {
- collect(invoker, invocation, null, RpcContext.getContext().getRemoteHost(), (long) invocation.get(MONITOR_FILTER_START_TIME), true);
+ collect(invoker, invocation, null, (String) invocation.get(MONITOR_REMOTE_HOST_STORE), (long) invocation.get(MONITOR_FILTER_START_TIME), true);
getConcurrent(invoker, invocation).decrementAndGet(); // count down
}
}
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Ready.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Ready.java
index 06457f6..7f7dd1a 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Ready.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Ready.java
@@ -21,7 +21,7 @@
import org.apache.dubbo.qos.command.CommandContext;
import org.apache.dubbo.qos.command.annotation.Cmd;
-@Cmd(name = "start",summary = "Judge if service has started? ")
+@Cmd(name = "ready",summary = "Judge if service has started? ")
public class Ready implements BaseCommand {
@Override
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/ListTelnetHandler.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/ListTelnetHandler.java
index 3da6cf4..02cd3b2 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/ListTelnetHandler.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/ListTelnetHandler.java
@@ -112,6 +112,7 @@
buf.append(" addresses: ");
buf.append(ServiceCheckUtils.getConsumerAddressNum(consumer));
}
+ buf.append("\r\n");
}
}
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/LogTelnetHandler.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/LogTelnetHandler.java
index c77c86c..3cbfc83 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/LogTelnetHandler.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/LogTelnetHandler.java
@@ -44,7 +44,7 @@
public String telnet(Channel channel, String message) {
long size;
File file = LoggerFactory.getFile();
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
if (message == null || message.trim().length() == 0) {
buf.append("EXAMPLE: log error / log 100");
} else {
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/AbstractServiceDiscovery.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/AbstractServiceDiscovery.java
index bebc73a..b5b0999 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/AbstractServiceDiscovery.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/AbstractServiceDiscovery.java
@@ -27,6 +27,7 @@
@Override
public void register(ServiceInstance serviceInstance) throws RuntimeException {
+ this.serviceInstance = serviceInstance;
}
@Override
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceInstance.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceInstance.java
index eb581f9..2cd28ea 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceInstance.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceInstance.java
@@ -174,8 +174,12 @@
@Override
public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof DefaultServiceInstance)) return false;
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof DefaultServiceInstance)) {
+ return false;
+ }
DefaultServiceInstance that = (DefaultServiceInstance) o;
boolean equals = Objects.equals(getServiceName(), that.getServiceName()) &&
Objects.equals(getHost(), that.getHost()) &&
@@ -184,7 +188,7 @@
if (entry.getKey().equals(REVISION_KEY)) {
continue;
}
- equals = equals && !entry.getValue().equals(that.getMetadata().get(entry.getKey()));
+ equals = equals && entry.getValue().equals(that.getMetadata().get(entry.getKey()));
}
return equals;
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 5159cfc..494785d 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
@@ -27,6 +27,7 @@
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.REMOTE_APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
public class InstanceAddressURL extends URL {
@@ -105,6 +106,8 @@
return getGroup();
} else if (INTERFACE_KEY.equals(key)) {
return getServiceInterface();
+ } else if (REMOTE_APPLICATION_KEY.equals(key)) {
+ return instance.getServiceName();
}
String protocolServiceKey = getProtocolServiceKey();
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscovery.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscovery.java
index 9800c35..3b6c4e5 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscovery.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscovery.java
@@ -217,6 +217,15 @@
}
/**
+ * unsubscribe to instances change event.
+ * @param listener
+ * @throws IllegalArgumentException
+ */
+ default void removeServiceInstancesChangedListener(ServiceInstancesChangedListener listener)
+ throws IllegalArgumentException {
+ }
+
+ /**
* Dispatch the {@link ServiceInstancesChangedEvent}
*
* @param serviceName the name of service whose service instances have been changed
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 a350590..e705c7c 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
@@ -52,6 +52,7 @@
import static java.util.Collections.unmodifiableSet;
import static java.util.stream.Collectors.toSet;
import static java.util.stream.Stream.of;
+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.GROUP_CHAR_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
@@ -111,6 +112,7 @@
/* apps - listener */
private final Map<String, ServiceInstancesChangedListener> serviceListeners = new HashMap<>();
+ private final Map<String, String> serviceToAppsMapping = new HashMap<>();
private URL registryURL;
@@ -258,9 +260,14 @@
public void doSubscribe(URL url, NotifyListener listener) {
writableMetadataService.subscribeURL(url);
+ boolean check = url.getParameter(CHECK_KEY, false);
Set<String> serviceNames = getServices(url, listener);
+
if (CollectionUtils.isEmpty(serviceNames)) {
- throw new IllegalStateException("Should has at least one way to know which services this interface belongs to, subscription url: " + url);
+ if (check) {
+ throw new IllegalStateException("Should has at least one way to know which services this interface belongs to, subscription url: " + url);
+ }
+ return;
}
subscribeURLs(url, listener, serviceNames);
@@ -280,6 +287,10 @@
public void doUnsubscribe(URL url, NotifyListener listener) {
writableMetadataService.unsubscribeURL(url);
+ String protocolServiceKey = url.getServiceKey() + GROUP_CHAR_SEPARATOR + url.getParameter(PROTOCOL_KEY, DUBBO);
+ String serviceNamesKey = serviceToAppsMapping.remove(protocolServiceKey);
+ ServiceInstancesChangedListener instancesChangedListener = serviceListeners.get(serviceNamesKey);
+ instancesChangedListener.removeListener(protocolServiceKey);
}
@Override
@@ -308,22 +319,30 @@
protected void subscribeURLs(URL url, NotifyListener listener, Set<String> serviceNames) {
String serviceNamesKey = serviceNames.toString();
+ String protocolServiceKey = url.getServiceKey() + GROUP_CHAR_SEPARATOR + url.getParameter(PROTOCOL_KEY, DUBBO);
+ serviceToAppsMapping.put(protocolServiceKey, serviceNamesKey);
+
// register ServiceInstancesChangedListener
ServiceInstancesChangedListener serviceListener = serviceListeners.computeIfAbsent(serviceNamesKey,
k -> new ServiceInstancesChangedListener(serviceNames, serviceDiscovery));
serviceListener.setUrl(url);
listener.addServiceListener(serviceListener);
- String protocolServiceKey = url.getServiceKey() + GROUP_CHAR_SEPARATOR + url.getParameter(PROTOCOL_KEY, DUBBO);
serviceListener.addListener(protocolServiceKey, listener);
registerServiceInstancesChangedListener(url, serviceListener);
+
serviceNames.forEach(serviceName -> {
List<ServiceInstance> serviceInstances = serviceDiscovery.getInstances(serviceName);
- serviceListener.onEvent(new ServiceInstancesChangedEvent(serviceName, serviceInstances));
+ if (CollectionUtils.isNotEmpty(serviceInstances)) {
+ serviceListener.onEvent(new ServiceInstancesChangedEvent(serviceName, serviceInstances));
+ } else {
+ logger.info("getInstances by serviceName=" + serviceName + " is empty, waiting for serviceListener callback. url=" + url);
+ }
});
listener.notify(serviceListener.getUrls(protocolServiceKey));
+
}
/**
@@ -356,17 +375,16 @@
String serviceNames = subscribedURL.getParameter(PROVIDED_BY);
if (StringUtils.isNotEmpty(serviceNames)) {
- subscribedServices.addAll(parseServices(serviceNames));
- }
-
- serviceNames = subscribedURL.getParameter(SUBSCRIBED_SERVICE_NAMES_KEY);
- if (StringUtils.isNotEmpty(serviceNames)) {
+ logger.info(subscribedURL.getServiceInterface() + " mapping to " + serviceNames + " instructed by provided-by set by user.");
subscribedServices.addAll(parseServices(serviceNames));
}
if (isEmpty(subscribedServices)) {
- subscribedServices.addAll(findMappedServices(subscribedURL, new DefaultMappingListener(subscribedURL, subscribedServices, listener)));
+ Set<String> mappedServices = findMappedServices(subscribedURL, new DefaultMappingListener(subscribedURL, subscribedServices, listener));
+ logger.info(subscribedURL.getServiceInterface() + " mapping to " + serviceNames + " instructed by remote metadata center.");
+ subscribedServices.addAll(mappedServices);
if (isEmpty(subscribedServices)) {
+ logger.info(subscribedURL.getServiceInterface() + " mapping to " + serviceNames + " by default.");
subscribedServices.addAll(getSubscribedServices());
}
}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryDirectory.java
index 15c187f..df573d1 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryDirectory.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryDirectory.java
@@ -127,6 +127,9 @@
logger.warn("destroyUnusedInvokers error. ", e);
}
}
+
+ // notify invokers refreshed
+ this.invokersChanged();
}
/**
@@ -199,7 +202,8 @@
/**
* Close all invokers
*/
- private void destroyAllInvokers() {
+ @Override
+ protected void destroyAllInvokers() {
Map<String, Invoker<T>> localUrlInvokerMap = this.urlInvokerMap; // local reference
if (localUrlInvokerMap != null) {
for (Invoker<T> invoker : new ArrayList<>(localUrlInvokerMap.values())) {
@@ -258,34 +262,4 @@
}
}
}
-
- @Override
- public void destroy() {
- if (isDestroyed()) {
- return;
- }
-
- // unregister.
- try {
- if (getRegisteredConsumerUrl() != null && registry != null && registry.isAvailable()) {
- registry.unregister(getRegisteredConsumerUrl());
- }
- } catch (Throwable t) {
- logger.warn("unexpected error when unregister service " + serviceKey + "from registry" + registry.getUrl(), t);
- }
- // unsubscribe.
- try {
- if (getConsumerUrl() != null && registry != null && registry.isAvailable()) {
- registry.unsubscribe(getConsumerUrl(), this);
- }
- } catch (Throwable t) {
- logger.warn("unexpected error when unsubscribe service " + serviceKey + "from registry" + registry.getUrl(), t);
- }
- super.destroy(); // must be executed after unsubscribing
- try {
- destroyAllInvokers();
- } catch (Throwable t) {
- logger.warn("Failed to destroy service " + serviceKey, t);
- }
- }
}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryProtocolListener.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryProtocolListener.java
deleted file mode 100644
index bc9748c..0000000
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryProtocolListener.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.client;
-
-import org.apache.dubbo.registry.integration.RegistryProtocolListener;
-import org.apache.dubbo.rpc.Exporter;
-import org.apache.dubbo.rpc.Invoker;
-
-public class ServiceDiscoveryRegistryProtocolListener implements RegistryProtocolListener {
- @Override
- public void onExport(RegistryProtocol registryProtocol, Exporter<?> exporter) {
-
- }
-
- @Override
- public void onRefer(RegistryProtocol registryProtocol, Invoker<?> invoker) {
-
- }
-
- @Override
- public void onDestroy() {
-
- }
-}
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 e99b40c..07e1e37 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
@@ -88,10 +88,14 @@
logger.info("Received instance notification, serviceName: " + event.getServiceName() + ", instances: " + event.getServiceInstances().size());
String appName = event.getServiceName();
allInstances.put(appName, event.getServiceInstances());
+ if (logger.isDebugEnabled()) {
+ logger.debug(event.getServiceInstances().toString());
+ }
Map<String, List<ServiceInstance>> revisionToInstances = new HashMap<>();
Map<String, Set<String>> localServiceToRevisions = new HashMap<>();
Map<Set<String>, List<URL>> revisionsToUrls = new HashMap();
+ Map<String, List<URL>> tmpServiceUrls = new HashMap<>();
for (Map.Entry<String, List<ServiceInstance>> entry : allInstances.entrySet()) {
List<ServiceInstance> instances = entry.getValue();
for (ServiceInstance instance : instances) {
@@ -108,7 +112,7 @@
metadata = getMetadataInfo(instance);
logger.info("MetadataInfo for instance " + instance.getAddress() + "?revision=" + revision + " is " + metadata);
if (metadata != null) {
- revisionToMetadata.put(revision, getMetadataInfo(instance));
+ revisionToMetadata.put(revision, metadata);
} else {
}
@@ -123,25 +127,26 @@
// Set<String> set = localServiceToRevisions.computeIfAbsent(url.getServiceKey(), k -> new TreeSet<>());
// set.add(revision);
// }
-
- localServiceToRevisions.forEach((serviceKey, revisions) -> {
- List<URL> urls = revisionsToUrls.get(revisions);
- if (urls != null) {
- serviceUrls.put(serviceKey, urls);
- } else {
- urls = new ArrayList<>();
- for (String r : revisions) {
- for (ServiceInstance i : revisionToInstances.get(r)) {
- urls.add(i.toURL());
- }
- }
- revisionsToUrls.put(revisions, urls);
- serviceUrls.put(serviceKey, urls);
- }
- });
}
+
+ localServiceToRevisions.forEach((serviceKey, revisions) -> {
+ List<URL> urls = revisionsToUrls.get(revisions);
+ if (urls != null) {
+ tmpServiceUrls.put(serviceKey, urls);
+ } else {
+ urls = new ArrayList<>();
+ for (String r : revisions) {
+ for (ServiceInstance i : revisionToInstances.get(r)) {
+ urls.add(i.toURL());
+ }
+ }
+ revisionsToUrls.put(revisions, urls);
+ tmpServiceUrls.put(serviceKey, urls);
+ }
+ });
}
+ this.serviceUrls = tmpServiceUrls;
this.notifyAddressChanged();
}
@@ -161,6 +166,9 @@
instance.getExtendParams().putIfAbsent(REGISTRY_CLUSTER_KEY, RegistryClusterIdentifier.getExtension(url).consumerKey(url));
MetadataInfo metadataInfo;
try {
+ if (logger.isDebugEnabled()) {
+ logger.info("Instance " + instance.getAddress() + " is using metadata type " + metadataType);
+ }
if (REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) {
RemoteMetadataServiceImpl remoteMetadataService = MetadataUtils.getRemoteMetadataService();
metadataInfo = remoteMetadataService.getMetadata(instance);
@@ -168,6 +176,9 @@
MetadataService metadataServiceProxy = MetadataUtils.getMetadataServiceProxy(instance, serviceDiscovery);
metadataInfo = metadataServiceProxy.getMetadataInfo(ServiceInstanceMetadataUtils.getExportedServicesRevision(instance));
}
+ if (logger.isDebugEnabled()) {
+ logger.info("Metadata " + metadataInfo.toString());
+ }
} catch (Exception e) {
logger.error("Failed to load service metadata, metadta type is " + metadataType, e);
metadataInfo = null;
@@ -194,6 +205,13 @@
this.listeners.put(serviceKey, listener);
}
+ public void removeListener(String serviceKey) {
+ listeners.remove(serviceKey);
+ if (listeners.isEmpty()) {
+ serviceDiscovery.removeServiceInstancesChangedListener(this);
+ }
+ }
+
public List<URL> getUrls(String serviceKey) {
return toUrlsWithEmpty(serviceUrls.get(serviceKey));
}
@@ -225,8 +243,12 @@
@Override
public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof ServiceInstancesChangedListener)) return false;
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof ServiceInstancesChangedListener)) {
+ return false;
+ }
ServiceInstancesChangedListener that = (ServiceInstancesChangedListener) o;
return Objects.equals(getServiceNames(), that.getServiceNames());
}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataUtils.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataUtils.java
index 4684a27..0a6a106 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataUtils.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataUtils.java
@@ -71,7 +71,7 @@
}
public static MetadataService getMetadataServiceProxy(ServiceInstance instance, ServiceDiscovery serviceDiscovery) {
- String key = instance.getServiceName() + "##" + instance.getId() + "##" +
+ String key = instance.getServiceName() + "##" +
ServiceInstanceMetadataUtils.getExportedServicesRevision(instance);
return metadataServiceProxies.computeIfAbsent(key, k -> {
MetadataServiceURLBuilder builder = null;
@@ -81,10 +81,10 @@
Map<String, String> metadata = instance.getMetadata();
// METADATA_SERVICE_URLS_PROPERTY_NAME is a unique key exists only on instances of spring-cloud-alibaba.
String dubboURLsJSON = metadata.get(METADATA_SERVICE_URLS_PROPERTY_NAME);
- if (metadata.isEmpty() || StringUtils.isEmpty(dubboURLsJSON)) {
- builder = loader.getExtension(StandardMetadataServiceURLBuilder.NAME);
- } else {
+ if (StringUtils.isNotEmpty(dubboURLsJSON)) {
builder = loader.getExtension(SpringCloudMetadataServiceURLBuilder.NAME);
+ } else {
+ builder = loader.getExtension(StandardMetadataServiceURLBuilder.NAME);
}
List<URL> urls = builder.build(instance);
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/StandardMetadataServiceURLBuilder.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/StandardMetadataServiceURLBuilder.java
index 34dce94..c90eea0 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/StandardMetadataServiceURLBuilder.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/StandardMetadataServiceURLBuilder.java
@@ -19,12 +19,8 @@
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.URLBuilder;
import org.apache.dubbo.common.config.ConfigurationUtils;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.metadata.MetadataService;
import org.apache.dubbo.registry.client.ServiceInstance;
-import org.apache.dubbo.remoting.Constants;
-import org.apache.dubbo.rpc.model.ApplicationModel;
import java.util.ArrayList;
import java.util.List;
@@ -32,12 +28,10 @@
import static java.lang.String.valueOf;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.SIDE_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.metadata.MetadataConstants.DEFAULT_METADATA_TIMEOUT_VALUE;
import static org.apache.dubbo.metadata.MetadataConstants.METADATA_PROXY_TIMEOUT_KEY;
import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.getMetadataServiceURLsParams;
@@ -49,9 +43,7 @@
* @since 2.7.5
*/
public class StandardMetadataServiceURLBuilder implements MetadataServiceURLBuilder {
-
- private final Logger logger = LoggerFactory.getLogger(getClass());
-
+
public static final String NAME = "standard";
/**
@@ -71,66 +63,27 @@
String host = serviceInstance.getHost();
- if (paramsMap.isEmpty()) {
- // ServiceInstance Metadata is empty. Happened when registry not support metadata write.
- urls.add(generateUrlWithoutMetadata(serviceName, host));
- } else {
- for (Map.Entry<String, Map<String, String>> entry : paramsMap.entrySet()) {
- String protocol = entry.getKey();
- Map<String, String> params = entry.getValue();
+ for (Map.Entry<String, Map<String, String>> entry : paramsMap.entrySet()) {
+ String protocol = entry.getKey();
+ Map<String, String> params = entry.getValue();
+ int port = Integer.parseInt(params.get(PORT_KEY));
+ URLBuilder urlBuilder = new URLBuilder()
+ .setHost(host)
+ .setPort(port)
+ .setProtocol(protocol)
+ .setPath(MetadataService.class.getName())
+ .addParameter(TIMEOUT_KEY, ConfigurationUtils.get(METADATA_PROXY_TIMEOUT_KEY, DEFAULT_METADATA_TIMEOUT_VALUE))
+ .addParameter(SIDE_KEY, CONSUMER);
- urls.add(generateWithMetadata(serviceName, host, protocol, params));
- }
+ // add parameters
+ params.forEach((name, value) -> urlBuilder.addParameter(name, valueOf(value)));
+
+ // add the default parameters
+ urlBuilder.addParameter(GROUP_KEY, serviceName);
+
+ urls.add(urlBuilder.build());
}
return urls;
}
-
- private URL generateWithMetadata(String serviceName, String host, String protocol, Map<String, String> params) {
- int port = Integer.parseInt(params.get(PORT_KEY));
- URLBuilder urlBuilder = new URLBuilder()
- .setHost(host)
- .setPort(port)
- .setProtocol(protocol)
- .setPath(MetadataService.class.getName())
- .addParameter(TIMEOUT_KEY, ConfigurationUtils.get(METADATA_PROXY_TIMEOUT_KEY, DEFAULT_METADATA_TIMEOUT_VALUE))
- .addParameter(SIDE_KEY, CONSUMER);
-
- // add parameters
- params.forEach((name, value) -> urlBuilder.addParameter(name, valueOf(value)));
-
- // add the default parameters
- urlBuilder.addParameter(GROUP_KEY, serviceName);
- return urlBuilder.build();
- }
-
- private URL generateUrlWithoutMetadata(String serviceName, String host) {
- Integer port = ApplicationModel.getApplicationConfig().getMetadataServicePort();
-
- if (port == null || port < 1) {
- String message = "Metadata Service Port should be specified for consumer. " +
- "Please set dubbo.application.metadataServicePort and " +
- "make sure it has been set in provider side. " +
- "ServiceName: " + serviceName + " Host: " + host;
-
- logger.error(message);
- throw new IllegalStateException(message);
- }
-
- URLBuilder urlBuilder = new URLBuilder()
- .setHost(host)
- .setPort(port)
- .setProtocol(DUBBO_PROTOCOL)
- .setPath(MetadataService.class.getName())
- .addParameter(TIMEOUT_KEY, ConfigurationUtils.get(METADATA_PROXY_TIMEOUT_KEY, DEFAULT_METADATA_TIMEOUT_VALUE))
- .addParameter(Constants.RECONNECT_KEY, false)
- .addParameter(SIDE_KEY, CONSUMER)
- .addParameter(GROUP_KEY, serviceName)
- .addParameter(VERSION_KEY, MetadataService.VERSION);
-
- // add ServiceInstance Metadata notify support
- urlBuilder.addParameter("getAndListenServiceDiscoveryMetadata.1.callback", true);
-
- return urlBuilder.build();
- }
}
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 c2403ea..44c6bbc 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
@@ -20,7 +20,6 @@
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.metadata.MetadataChangeListener;
import org.apache.dubbo.metadata.MetadataInfo;
import org.apache.dubbo.metadata.MetadataInfo.ServiceInfo;
import org.apache.dubbo.metadata.MetadataService;
@@ -77,8 +76,6 @@
ConcurrentNavigableMap<String, SortedSet<URL>> exportedServiceURLs = new ConcurrentSkipListMap<>();
ConcurrentMap<String, MetadataInfo> metadataInfos;
final Semaphore metadataSemaphore = new Semaphore(1);
- String serviceDiscoveryMetadata;
- ConcurrentMap<String, MetadataChangeListener> metadataChangeListenerMap = new ConcurrentHashMap<>();
// ==================================================================================== //
@@ -209,22 +206,6 @@
return null;
}
- @Override
- public void exportServiceDiscoveryMetadata(String metadata) {
- this.serviceDiscoveryMetadata = metadata;
- }
-
- @Override
- public Map<String, MetadataChangeListener> getMetadataChangeListenerMap() {
- return metadataChangeListenerMap;
- }
-
- @Override
- public String getAndListenServiceDiscoveryMetadata(String consumerId, MetadataChangeListener listener) {
- metadataChangeListenerMap.put(consumerId, listener);
- return serviceDiscoveryMetadata;
- }
-
public void blockUntilUpdated() {
try {
metadataSemaphore.acquire();
@@ -310,4 +291,5 @@
return o1.toFullString().compareTo(o2.toFullString());
}
}
+
}
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 01c4eff..209a9fa 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
@@ -69,6 +69,10 @@
if (metadataReport == null) {
metadataReport = getMetadataReports().entrySet().iterator().next().getValue();
}
+ logger.info("Publishing metadata to " + metadataReport.getClass().getSimpleName());
+ if (logger.isDebugEnabled()) {
+ logger.debug(metadataInfo.toString());
+ }
metadataReport.publishAppMetadata(identifier, metadataInfo);
metadataInfo.markReported();
}
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
new file mode 100644
index 0000000..2936688
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/DefaultMigrationAddressComparator.java
@@ -0,0 +1,74 @@
+/*
+ * 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.client.migration;
+
+import org.apache.dubbo.common.config.ConfigurationUtils;
+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.rpc.Invoker;
+import org.apache.dubbo.rpc.cluster.ClusterInvoker;
+
+import java.util.List;
+
+public class DefaultMigrationAddressComparator implements MigrationAddressComparator {
+ private static final Logger logger = LoggerFactory.getLogger(DefaultMigrationAddressComparator.class);
+ private static final String MIGRATION_THRESHOLD = "dubbo.application.migration.threshold";
+ private static final String DEFAULT_THRESHOLD_STRING = "0.8";
+ private static final float DEFAULT_THREAD = 0.8f;
+
+ @Override
+ public <T> boolean shouldMigrate(ClusterInvoker<T> serviceDiscoveryInvoker, ClusterInvoker<T> invoker) {
+ if (!serviceDiscoveryInvoker.isAvailable()) {
+ logger.info("No instance address available, will not migrate.");
+ return false;
+ }
+ if (!invoker.isAvailable()) {
+ logger.info("No interface address available, will migrate.");
+ return true;
+ }
+
+ List<Invoker<T>> invokers1 = serviceDiscoveryInvoker.getDirectory().getAllInvokers();
+ List<Invoker<T>> invokers2 = invoker.getDirectory().getAllInvokers();
+
+ int newAddressSize = CollectionUtils.isNotEmpty(invokers1) ? invokers1.size() : 0;
+ int oldAddressSize = CollectionUtils.isNotEmpty(invokers2) ? invokers2.size() : 0;
+
+ String rawThreshold = ConfigurationUtils.getDynamicProperty(MIGRATION_THRESHOLD, DEFAULT_THRESHOLD_STRING);
+ float threshold;
+ try {
+ threshold = Float.parseFloat(rawThreshold);
+ } catch (Exception e) {
+ logger.error("Invalid migration threshold " + rawThreshold);
+ threshold = DEFAULT_THREAD;
+ }
+
+ logger.info("Instance address size " + newAddressSize + ", interface address size " + oldAddressSize + ", threshold " + threshold);
+
+ if (newAddressSize != 0 && oldAddressSize == 0) {
+ return true;
+ }
+ if (newAddressSize == 0 && oldAddressSize == 0) {
+ return false;
+ }
+
+ if (((float)newAddressSize / (float)oldAddressSize) >= threshold) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/InvokersChangedListener.java
similarity index 86%
copy from dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java
copy to dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/InvokersChangedListener.java
index 2042277..74cd947 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/InvokersChangedListener.java
@@ -14,7 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.common;
+package org.apache.dubbo.registry.client.migration;
-public class ConfigurationURL extends URL {
-}
+public interface InvokersChangedListener {
+ void onChange();
+}
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationAddressComparator.java
similarity index 72%
copy from dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java
copy to dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationAddressComparator.java
index 2042277..2be527b 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationAddressComparator.java
@@ -14,7 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.common;
+package org.apache.dubbo.registry.client.migration;
-public class ConfigurationURL extends URL {
+import org.apache.dubbo.common.extension.SPI;
+import org.apache.dubbo.rpc.cluster.ClusterInvoker;
+
+@SPI
+public interface MigrationAddressComparator {
+ <T> boolean shouldMigrate(ClusterInvoker<T> serviceDiscoveryInvoker, ClusterInvoker<T> invoker);
}
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
new file mode 100644
index 0000000..b3c9f68
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationInvoker.java
@@ -0,0 +1,390 @@
+/*
+ * 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.client.migration;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.RegistryConstants;
+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.utils.StringUtils;
+import org.apache.dubbo.registry.Registry;
+import org.apache.dubbo.registry.integration.DynamicDirectory;
+import org.apache.dubbo.registry.integration.RegistryProtocol;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Cluster;
+import org.apache.dubbo.rpc.cluster.ClusterInvoker;
+import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.rpc.cluster.support.migration.MigrationClusterInvoker;
+import org.apache.dubbo.rpc.cluster.support.migration.MigrationRule;
+
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
+
+public class MigrationInvoker<T> implements MigrationClusterInvoker<T> {
+ private Logger logger = LoggerFactory.getLogger(MigrationInvoker.class);
+
+ private URL url;
+ private URL consumerUrl;
+ private Cluster cluster;
+ private Registry registry;
+ private Class<T> type;
+ private RegistryProtocol registryProtocol;
+
+ private volatile ClusterInvoker<T> invoker;
+ private volatile ClusterInvoker<T> serviceDiscoveryInvoker;
+ private volatile ClusterInvoker<T> currentAvailableInvoker;
+
+ private MigrationRule rule;
+
+ private boolean migrationMultiRegsitry;
+
+ public MigrationInvoker(RegistryProtocol registryProtocol,
+ Cluster cluster,
+ Registry registry,
+ Class<T> type,
+ URL url,
+ URL consumerUrl) {
+ this(null, null, registryProtocol, cluster, registry, type, url, consumerUrl);
+ }
+
+ public MigrationInvoker(ClusterInvoker<T> invoker,
+ ClusterInvoker<T> serviceDiscoveryInvoker,
+ RegistryProtocol registryProtocol,
+ Cluster cluster,
+ Registry registry,
+ Class<T> type,
+ URL url,
+ URL consumerUrl) {
+ this.invoker = invoker;
+ this.serviceDiscoveryInvoker = serviceDiscoveryInvoker;
+ this.registryProtocol = registryProtocol;
+ this.cluster = cluster;
+ this.registry = registry;
+ this.type = type;
+ this.url = url;
+ this.consumerUrl = consumerUrl;
+ this.migrationMultiRegsitry = url.getParameter("MIGRATION_MULTI_REGSITRY", RegistryConstants.MIGRATION_MULTI_REGSITRY);
+ }
+
+ public ClusterInvoker<T> getInvoker() {
+ return invoker;
+ }
+
+ public void setInvoker(ClusterInvoker<T> invoker) {
+ this.invoker = invoker;
+ }
+
+ public ClusterInvoker<T> getServiceDiscoveryInvoker() {
+ return serviceDiscoveryInvoker;
+ }
+
+ public void setServiceDiscoveryInvoker(ClusterInvoker<T> serviceDiscoveryInvoker) {
+ this.serviceDiscoveryInvoker = serviceDiscoveryInvoker;
+ }
+
+ @Override
+ public Class<T> getInterface() {
+ return type;
+ }
+
+ @Override
+ public synchronized void migrateToServiceDiscoveryInvoker(boolean forceMigrate) {
+ if (!forceMigrate) {
+ refreshServiceDiscoveryInvoker();
+ refreshInterfaceInvoker();
+ setListener(invoker, () -> {
+ this.compareAddresses(invoker, serviceDiscoveryInvoker);
+ });
+ setListener(serviceDiscoveryInvoker, () -> {
+ this.compareAddresses(invoker, serviceDiscoveryInvoker);
+ });
+ } else {
+ refreshServiceDiscoveryInvoker();
+ setListener(serviceDiscoveryInvoker, () -> {
+ this.destroyInterfaceInvoker(this.invoker);
+ });
+ }
+ }
+
+ @Override
+ public void reRefer(URL newSubscribeUrl) {
+ // update url to prepare for migration refresh
+ this.url = url.addParameter(REFER_KEY, StringUtils.toQueryString(newSubscribeUrl.getParameters()));
+
+ // re-subscribe immediately
+ if (invoker != null && !invoker.isDestroyed()) {
+ doReSubscribe(invoker, newSubscribeUrl);
+ }
+ if (serviceDiscoveryInvoker != null && !serviceDiscoveryInvoker.isDestroyed()) {
+ doReSubscribe(serviceDiscoveryInvoker, newSubscribeUrl);
+ }
+ }
+
+ private void doReSubscribe(ClusterInvoker<T> invoker, URL newSubscribeUrl) {
+ DynamicDirectory<T> directory = (DynamicDirectory<T>)invoker.getDirectory();
+ URL oldSubscribeUrl = directory.getRegisteredConsumerUrl();
+ Registry registry = directory.getRegistry();
+ registry.unregister(directory.getRegisteredConsumerUrl());
+ directory.unSubscribe(RegistryProtocol.toSubscribeUrl(oldSubscribeUrl));
+ registry.register(directory.getRegisteredConsumerUrl());
+
+ directory.setRegisteredConsumerUrl(newSubscribeUrl);
+ directory.buildRouterChain(newSubscribeUrl);
+ directory.subscribe(RegistryProtocol.toSubscribeUrl(newSubscribeUrl));
+ }
+
+ @Override
+ public synchronized void fallbackToInterfaceInvoker() {
+ refreshInterfaceInvoker();
+ setListener(invoker, () -> {
+ this.destroyServiceDiscoveryInvoker(this.serviceDiscoveryInvoker);
+ });
+ }
+
+ @Override
+ public Result invoke(Invocation invocation) throws RpcException {
+ if (!checkInvokerAvailable(serviceDiscoveryInvoker)) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Using interface addresses to handle invocation, interface " + type.getName() + ", total address size " + (invoker.getDirectory().getAllInvokers() == null ? "is null" : invoker.getDirectory().getAllInvokers().size()));
+ }
+ return invoker.invoke(invocation);
+ }
+
+ if (!checkInvokerAvailable(invoker)) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Using instance addresses to handle invocation, interface " + type.getName() + ", total address size " + (serviceDiscoveryInvoker.getDirectory().getAllInvokers() == null ? " is null " : serviceDiscoveryInvoker.getDirectory().getAllInvokers().size()));
+ }
+ return serviceDiscoveryInvoker.invoke(invocation);
+ }
+
+ return currentAvailableInvoker.invoke(invocation);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return (invoker != null && invoker.isAvailable())
+ || (serviceDiscoveryInvoker != null && serviceDiscoveryInvoker.isAvailable());
+ }
+
+ @Override
+ public void destroy() {
+ if (invoker != null) {
+ invoker.destroy();
+ }
+ if (serviceDiscoveryInvoker != null) {
+ serviceDiscoveryInvoker.destroy();
+ }
+ }
+
+ @Override
+ public URL getUrl() {
+ if (invoker != null) {
+ return invoker.getUrl();
+ } else if (serviceDiscoveryInvoker != null) {
+ return serviceDiscoveryInvoker.getUrl();
+ }
+
+ return consumerUrl;
+ }
+
+ @Override
+ public URL getRegistryUrl() {
+ if (invoker != null) {
+ return invoker.getRegistryUrl();
+ } else if (serviceDiscoveryInvoker != null) {
+ serviceDiscoveryInvoker.getRegistryUrl();
+ }
+ return url;
+ }
+
+ @Override
+ public Directory<T> getDirectory() {
+ if (invoker != null) {
+ return invoker.getDirectory();
+ } else if (serviceDiscoveryInvoker != null) {
+ return serviceDiscoveryInvoker.getDirectory();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isDestroyed() {
+ return (invoker == null || invoker.isDestroyed())
+ && (serviceDiscoveryInvoker == null || serviceDiscoveryInvoker.isDestroyed());
+ }
+
+
+ @Override
+ public AtomicBoolean invokersChanged() {
+ return invokersChanged;
+ }
+
+ private volatile AtomicBoolean invokersChanged = new AtomicBoolean(true);
+
+ private synchronized void compareAddresses(ClusterInvoker<T> serviceDiscoveryInvoker, ClusterInvoker<T> invoker) {
+ this.invokersChanged.set(true);
+ if (logger.isDebugEnabled()) {
+ logger.info(invoker.getDirectory().getAllInvokers() == null ? "null" :invoker.getDirectory().getAllInvokers().size() + "");
+ }
+
+ Set<MigrationAddressComparator> detectors = ExtensionLoader.getExtensionLoader(MigrationAddressComparator.class).getSupportedExtensionInstances();
+ if (detectors != null && detectors.stream().allMatch(migrationDetector -> migrationDetector.shouldMigrate(serviceDiscoveryInvoker, invoker))) {
+ discardInterfaceInvokerAddress(invoker);
+ } else {
+ discardServiceDiscoveryInvokerAddress(serviceDiscoveryInvoker);
+ }
+ }
+
+ private synchronized void setAddressChanged() {
+ this.invokersChanged.set(true);
+ }
+
+ public synchronized void destroyServiceDiscoveryInvoker(ClusterInvoker<?> serviceDiscoveryInvoker) {
+ if (checkInvokerAvailable(this.invoker)) {
+ this.currentAvailableInvoker = this.invoker;
+ }
+ if (serviceDiscoveryInvoker != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Destroying instance address invokers, will not listen for address changes until re-subscribed, " + type.getName());
+ }
+ serviceDiscoveryInvoker.destroy();
+ }
+ }
+
+ public synchronized void discardServiceDiscoveryInvokerAddress(ClusterInvoker<?> serviceDiscoveryInvoker) {
+ if (checkInvokerAvailable(this.invoker)) {
+ this.currentAvailableInvoker = this.invoker;
+ }
+ if (serviceDiscoveryInvoker != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Discarding instance addresses, total size " + (null == serviceDiscoveryInvoker.getDirectory().getAllInvokers() ? "null" : serviceDiscoveryInvoker.getDirectory().getAllInvokers().size()));
+ }
+ serviceDiscoveryInvoker.getDirectory().discordAddresses();
+ }
+ }
+
+ public synchronized void refreshServiceDiscoveryInvoker() {
+ clearListener(serviceDiscoveryInvoker);
+ if (needRefresh(serviceDiscoveryInvoker)) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Re-subscribing instance addresses, current interface " + type.getName());
+ }
+ serviceDiscoveryInvoker = registryProtocol.getServiceDiscoveryInvoker(cluster, registry, type, url);
+
+ if (migrationMultiRegsitry) {
+ setListener(serviceDiscoveryInvoker, () -> {
+ this.setAddressChanged();
+ });
+ }
+ }
+ }
+
+ private void clearListener(ClusterInvoker<T> invoker) {
+ if (migrationMultiRegsitry) {
+ return;
+ }
+
+ if (invoker == null) {
+ return;
+ }
+ DynamicDirectory<T> directory = (DynamicDirectory<T>) invoker.getDirectory();
+ directory.setInvokersChangedListener(null);
+ }
+
+ private void setListener(ClusterInvoker<T> invoker, InvokersChangedListener listener) {
+ if (invoker == null) {
+ return;
+ }
+ DynamicDirectory<T> directory = (DynamicDirectory<T>) invoker.getDirectory();
+ directory.setInvokersChangedListener(listener);
+ }
+
+ public synchronized void refreshInterfaceInvoker() {
+ clearListener(invoker);
+ if (needRefresh(invoker)) {
+ // FIXME invoker.destroy();
+ if (logger.isDebugEnabled()) {
+ logger.debug("Re-subscribing interface addresses for interface " + type.getName());
+ }
+ invoker = registryProtocol.getInvoker(cluster, registry, type, url);
+
+ if (migrationMultiRegsitry) {
+ setListener(serviceDiscoveryInvoker, () -> {
+ this.setAddressChanged();
+ });
+ }
+ }
+ }
+
+ public synchronized void destroyInterfaceInvoker(ClusterInvoker<T> invoker) {
+ if (checkInvokerAvailable(this.serviceDiscoveryInvoker)) {
+ this.currentAvailableInvoker = this.serviceDiscoveryInvoker;
+ }
+ if (invoker != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Destroying interface address invokers, will not listen for address changes until re-subscribed, " + type.getName());
+ }
+ invoker.destroy();
+ }
+ }
+
+ public synchronized void discardInterfaceInvokerAddress(ClusterInvoker<T> invoker) {
+ if (this.serviceDiscoveryInvoker != null) {
+ this.currentAvailableInvoker = this.serviceDiscoveryInvoker;
+ }
+ if (invoker != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Discarding interface addresses, total address size " + (null == invoker.getDirectory().getAllInvokers() ? "null": invoker.getDirectory().getAllInvokers().size()));
+ }
+ invoker.getDirectory().discordAddresses();
+ }
+ }
+
+ private boolean needRefresh(ClusterInvoker<T> invoker) {
+ return invoker == null || invoker.isDestroyed();
+ }
+
+ public boolean checkInvokerAvailable(ClusterInvoker<T> invoker) {
+ return invoker != null && !invoker.isDestroyed() && invoker.isAvailable();
+ }
+
+ @Override
+ public boolean isServiceInvoker() {
+ return false;
+ }
+
+ @Override
+ public MigrationRule getMigrationRule() {
+ return rule;
+ }
+
+ @Override
+ public void setMigrationRule(MigrationRule rule) {
+ this.rule = rule;
+ }
+
+ @Override
+ public boolean isMigrationMultiRegsitry() {
+ return migrationMultiRegsitry;
+ }
+
+}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationRuleHandler.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationRuleHandler.java
new file mode 100644
index 0000000..faf3d86
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationRuleHandler.java
@@ -0,0 +1,71 @@
+/*
+ * 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.client.migration;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.rpc.cluster.support.migration.MigrationRule;
+import org.apache.dubbo.rpc.cluster.support.migration.MigrationStep;
+
+@Activate
+public class MigrationRuleHandler<T> {
+ private static final Logger logger = LoggerFactory.getLogger(MigrationRuleHandler.class);
+
+ private MigrationInvoker<T> migrationInvoker;
+
+ public MigrationRuleHandler(MigrationInvoker<T> invoker) {
+ this.migrationInvoker = invoker;
+ }
+
+ private MigrationStep currentStep;
+
+ public void doMigrate(String rawRule) {
+ MigrationRule rule = MigrationRule.parse(rawRule);
+
+ if (null != currentStep && currentStep.equals(rule.getStep())) {
+ if (logger.isInfoEnabled()) {
+ logger.info("Migration step is not change. rule.getStep is " + currentStep.name());
+ }
+ return;
+ } else {
+ currentStep = rule.getStep();
+ }
+
+ migrationInvoker.setMigrationRule(rule);
+
+ if (migrationInvoker.isMigrationMultiRegsitry()) {
+ if (migrationInvoker.isServiceInvoker()) {
+ migrationInvoker.refreshServiceDiscoveryInvoker();
+ } else {
+ migrationInvoker.refreshInterfaceInvoker();
+ }
+ } else {
+ switch (rule.getStep()) {
+ case APPLICATION_FIRST:
+ migrationInvoker.migrateToServiceDiscoveryInvoker(false);
+ break;
+ case FORCE_APPLICATION:
+ migrationInvoker.migrateToServiceDiscoveryInvoker(true);
+ break;
+ case FORCE_INTERFACE:
+ default:
+ migrationInvoker.fallbackToInterfaceInvoker();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationRuleListener.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationRuleListener.java
new file mode 100644
index 0000000..e0cb6ce
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationRuleListener.java
@@ -0,0 +1,112 @@
+/*
+ * 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.client.migration;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
+import org.apache.dubbo.common.config.configcenter.ConfigurationListener;
+import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
+import org.apache.dubbo.common.extension.Activate;
+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.StringUtils;
+import org.apache.dubbo.registry.integration.RegistryProtocol;
+import org.apache.dubbo.registry.integration.RegistryProtocolListener;
+import org.apache.dubbo.rpc.Exporter;
+import org.apache.dubbo.rpc.cluster.ClusterInvoker;
+import org.apache.dubbo.rpc.cluster.support.migration.MigrationRule;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+
+import java.util.Optional;
+import java.util.Set;
+
+import static org.apache.dubbo.common.constants.RegistryConstants.INIT;
+
+@Activate
+public class MigrationRuleListener implements RegistryProtocolListener, ConfigurationListener {
+ private static final Logger logger = LoggerFactory.getLogger(MigrationRuleListener.class);
+
+ private Set<MigrationRuleHandler> listeners = new ConcurrentHashSet<>();
+ private DynamicConfiguration configuration;
+
+ private volatile String rawRule;
+
+ public MigrationRuleListener() {
+ Optional<DynamicConfiguration> optional = ApplicationModel.getEnvironment().getDynamicConfiguration();
+
+ if (optional.isPresent()) {
+ this.configuration = optional.orElseGet(null);
+
+ logger.info("Listening for migration rules on dataId-" + MigrationRule.RULE_KEY + " group-" + MigrationRule.DUBBO_SERVICEDISCOVERY_MIGRATION_GROUP);
+ configuration.addListener(MigrationRule.RULE_KEY, MigrationRule.DUBBO_SERVICEDISCOVERY_MIGRATION_GROUP, this);
+
+ rawRule = configuration.getConfig(MigrationRule.RULE_KEY, MigrationRule.DUBBO_SERVICEDISCOVERY_MIGRATION_GROUP);
+ if (StringUtils.isEmpty(rawRule)) {
+ rawRule = INIT;
+ }
+
+ } else {
+ if (logger.isWarnEnabled()) {
+ logger.warn("configceneter is not configured!");
+ }
+
+ rawRule = INIT;
+ }
+
+ process(new ConfigChangedEvent(MigrationRule.RULE_KEY, MigrationRule.DUBBO_SERVICEDISCOVERY_MIGRATION_GROUP, rawRule));
+ }
+
+ @Override
+ public synchronized void process(ConfigChangedEvent event) {
+ rawRule = event.getContent();
+ if (StringUtils.isEmpty(rawRule)) {
+ logger.warn("Received empty migration rule, will ignore.");
+ return;
+ }
+
+ logger.info("Using the following migration rule to migrate:");
+ logger.info(rawRule);
+
+ if (CollectionUtils.isNotEmpty(listeners)) {
+ listeners.forEach(listener -> listener.doMigrate(rawRule));
+ }
+ }
+
+ @Override
+ public synchronized void onExport(RegistryProtocol registryProtocol, Exporter<?> exporter) {
+
+ }
+
+ @Override
+ public synchronized void onRefer(RegistryProtocol registryProtocol, ClusterInvoker<?> invoker, URL url) {
+ MigrationInvoker<?> migrationInvoker = (MigrationInvoker<?>) invoker;
+
+ MigrationRuleHandler<?> migrationListener = new MigrationRuleHandler<>(migrationInvoker);
+ listeners.add(migrationListener);
+
+ migrationListener.doMigrate(rawRule);
+ }
+
+ @Override
+ public void onDestroy() {
+ if (null != configuration) {
+ configuration.removeListener(MigrationRule.RULE_KEY, this);
+ }
+ }
+}
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/ServiceDiscoveryMigrationInvoker.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/ServiceDiscoveryMigrationInvoker.java
new file mode 100644
index 0000000..feeb5b8
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/ServiceDiscoveryMigrationInvoker.java
@@ -0,0 +1,61 @@
+/*
+ * 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.client.migration;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.registry.Registry;
+import org.apache.dubbo.registry.integration.RegistryProtocol;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Cluster;
+import org.apache.dubbo.rpc.cluster.ClusterInvoker;
+
+public class ServiceDiscoveryMigrationInvoker<T> extends MigrationInvoker<T> {
+ private static final Logger logger = LoggerFactory.getLogger(ServiceDiscoveryMigrationInvoker.class);
+
+ public ServiceDiscoveryMigrationInvoker(RegistryProtocol registryProtocol, Cluster cluster, Registry registry, Class<T> type, URL url, URL consumerUrl) {
+ super(registryProtocol, cluster, registry, type, url, consumerUrl);
+ }
+
+ @Override
+ public boolean isServiceInvoker() {
+ return true;
+ }
+
+ @Override
+ public synchronized void fallbackToInterfaceInvoker() {
+ logger.error("Service discovery registry type does not support discovery of interface level addresses, " + getRegistryUrl());
+ migrateToServiceDiscoveryInvoker(true);
+ }
+
+ @Override
+ public synchronized void migrateToServiceDiscoveryInvoker(boolean forceMigrate) {
+ refreshServiceDiscoveryInvoker();
+ }
+
+ @Override
+ public Result invoke(Invocation invocation) throws RpcException {
+ ClusterInvoker<T> invoker = getServiceDiscoveryInvoker();
+ if (invoker == null) {
+ throw new IllegalStateException("There's no service discovery invoker available for service " + invocation.getServiceName());
+ }
+ return invoker.invoke(invocation);
+ }
+}
\ No newline at end of file
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 b6c0038..31323ef 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,6 +17,7 @@
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;
@@ -25,6 +26,7 @@
import org.apache.dubbo.registry.NotifyListener;
import org.apache.dubbo.registry.Registry;
import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;
+import org.apache.dubbo.registry.client.migration.InvokersChangedListener;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Protocol;
@@ -35,19 +37,21 @@
import org.apache.dubbo.rpc.cluster.RouterFactory;
import org.apache.dubbo.rpc.cluster.directory.AbstractDirectory;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import java.util.Set;
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;
+import static org.apache.dubbo.registry.integration.RegistryProtocol.DEFAULT_REGISTER_CONSUMER_KEYS;
import static org.apache.dubbo.remoting.Constants.CHECK_KEY;
@@ -65,6 +69,7 @@
protected final String serviceKey; // Initialization at construction time, assertion not null
protected final Class<T> serviceType; // Initialization at construction time, assertion not null
+ protected final URL directoryUrl; // Initialization at construction time, assertion not null, and always assign non null value
protected final boolean multiGroup;
protected Protocol protocol; // Initialization at the time of injection, the assertion is not null
protected Registry registry; // Initialization at the time of injection, the assertion is not null
@@ -72,7 +77,7 @@
protected boolean shouldRegister;
protected boolean shouldSimplified;
- protected volatile URL overrideConsumerUrl; // Initialization at construction time, assertion not null, and always assign non null value
+ protected volatile URL overrideDirectoryUrl; // Initialization at construction time, assertion not null, and always assign non null value
protected volatile URL registeredConsumerUrl;
@@ -84,17 +89,13 @@
*/
protected volatile List<Configurator> configurators; // The initial value is null and the midway may be assigned to null, please use the local variable reference
- // Map<url, Invoker> cache service url to invoker mapping.
- protected volatile Map<URL, Invoker<T>> urlInvokerMap; // The initial value is null and the midway may be assigned to null, please use the local variable reference
protected volatile List<Invoker<T>> invokers;
-
// Set<invokerUrls> cache invokeUrls to invokers mapping.
- protected volatile Set<URL> cachedInvokerUrls; // The initial value is null and the midway may be assigned to null, please use the local variable reference
protected ServiceInstancesChangedListener serviceListener;
public DynamicDirectory(Class<T> serviceType, URL url) {
- super(url);
+ super(url, true);
if (serviceType == null) {
throw new IllegalArgumentException("service type is null.");
}
@@ -107,7 +108,8 @@
this.serviceType = serviceType;
this.serviceKey = super.getConsumerUrl().getServiceKey();
- String group = queryMap.get(GROUP_KEY) != null ? queryMap.get(GROUP_KEY) : "";
+ this.overrideDirectoryUrl = this.directoryUrl = turnRegistryUrlToConsumerUrl(url);
+ String group = directoryUrl.getParameter(GROUP_KEY, "");
this.multiGroup = group != null && (ANY_VALUE.equals(group) || group.contains(","));
}
@@ -116,6 +118,18 @@
this.serviceListener = instanceListener;
}
+ private URL turnRegistryUrlToConsumerUrl(URL url) {
+ return URLBuilder.from(url)
+ .setHost(queryMap.get(REGISTER_IP_KEY) == null ? url.getHost() : 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;
}
@@ -177,6 +191,11 @@
return invokers;
}
+ @Override
+ public URL getConsumerUrl() {
+ return this.overrideDirectoryUrl;
+ }
+
public URL getRegisteredConsumerUrl() {
return registeredConsumerUrl;
}
@@ -191,41 +210,74 @@
}
}
- @Override
- public boolean isAvailable() {
- if (isDestroyed()) {
- return false;
- }
- Map<URL, Invoker<T>> localUrlInvokerMap = urlInvokerMap;
- if (localUrlInvokerMap != null && localUrlInvokerMap.size() > 0) {
- for (Invoker<T> invoker : new ArrayList<>(localUrlInvokerMap.values())) {
- if (invoker.isAvailable()) {
- return true;
- }
- }
- }
- return false;
- }
-
public void buildRouterChain(URL url) {
this.setRouterChain(RouterChain.buildChain(url));
}
- /**
- * Haomin: added for test purpose
- */
- public Map<URL, Invoker<T>> getUrlInvokerMap() {
- return urlInvokerMap;
- }
-
public List<Invoker<T>> getInvokers() {
return invokers;
}
@Override
- public void setConsumerUrl(URL consumerUrl) {
- this.consumerUrl = consumerUrl;
- this.overrideConsumerUrl = consumerUrl;
+ public void destroy() {
+ if (isDestroyed()) {
+ return;
+ }
+
+ // unregister.
+ try {
+ if (getRegisteredConsumerUrl() != null && registry != null && registry.isAvailable()) {
+ registry.unregister(getRegisteredConsumerUrl());
+ }
+ } catch (Throwable t) {
+ logger.warn("unexpected error when unregister service " + serviceKey + "from registry" + registry.getUrl(), t);
+ }
+ // unsubscribe.
+ try {
+ if (getConsumerUrl() != null && registry != null && registry.isAvailable()) {
+ registry.unsubscribe(getConsumerUrl(), this);
+ }
+ } catch (Throwable t) {
+ logger.warn("unexpected error when unsubscribe service " + serviceKey + "from registry" + registry.getUrl(), t);
+ }
+ super.destroy(); // must be executed after unsubscribing
+ try {
+ destroyAllInvokers();
+ } catch (Throwable t) {
+ logger.warn("Failed to destroy service " + serviceKey, t);
+ }
+
+ invokersChangedListener = null;
}
+ @Override
+ public void discordAddresses() {
+ try {
+ destroyAllInvokers();
+ } catch (Throwable t) {
+ logger.warn("Failed to destroy service " + serviceKey, t);
+ }
+ }
+
+ private volatile InvokersChangedListener invokersChangedListener;
+ private volatile boolean addressChanged;
+
+ public void setInvokersChangedListener(InvokersChangedListener listener) {
+ this.invokersChangedListener = listener;
+ if (addressChanged) {
+ invokersChangedListener.onChange();
+ this.addressChanged = false;
+ }
+ }
+
+ protected void invokersChanged() {
+ if (invokersChangedListener != null) {
+ invokersChangedListener.onChange();
+ this.addressChanged = false;
+ } else {
+ this.addressChanged = true;
+ }
+ }
+
+ protected abstract void destroyAllInvokers();
}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/InterfaceCompatibleRegistryProtocol.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/InterfaceCompatibleRegistryProtocol.java
index 0a06762..b7374a3 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/InterfaceCompatibleRegistryProtocol.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/InterfaceCompatibleRegistryProtocol.java
@@ -19,24 +19,15 @@
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.URLBuilder;
import org.apache.dubbo.registry.Registry;
-import org.apache.dubbo.registry.client.RegistryProtocol;
-import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.registry.client.ServiceDiscoveryRegistryDirectory;
+import org.apache.dubbo.registry.client.migration.MigrationInvoker;
import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Cluster;
import org.apache.dubbo.rpc.cluster.ClusterInvoker;
-import org.apache.dubbo.rpc.cluster.Directory;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_REGISTRY_DIRECTORY_AUTO_MIGRATION;
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.registry.Constants.CONSUMER_PROTOCOL;
import static org.apache.dubbo.registry.Constants.DEFAULT_REGISTRY;
-import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
/**
* RegistryProtocol
@@ -62,126 +53,21 @@
}
@Override
- protected <T> DynamicDirectory<T> createDirectory(Class<T> type, URL url) {
- return new RegistryDirectory<>(type, url);
+ public <T> ClusterInvoker<T> getInvoker(Cluster cluster, Registry registry, Class<T> type, URL url) {
+ DynamicDirectory<T> directory = new RegistryDirectory<>(type, url);
+ return doCreateInvoker(directory, cluster, registry, type);
}
- protected <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
- ClusterInvoker<T> invoker = getInvoker(cluster, registry, type, url);
- ClusterInvoker<T> serviceDiscoveryInvoker = getServiceDiscoveryInvoker(cluster, type, url);
- ClusterInvoker<T> migrationInvoker = new MigrationInvoker<>(invoker, serviceDiscoveryInvoker);
-
- return interceptInvoker(migrationInvoker, url);
+ @Override
+ public <T> ClusterInvoker<T> getServiceDiscoveryInvoker(Cluster cluster, Registry registry, Class<T> type, URL url) {
+ registry = registryFactory.getRegistry(super.getRegistryUrl(url));
+ DynamicDirectory<T> directory = new ServiceDiscoveryRegistryDirectory<>(type, url);
+ return doCreateInvoker(directory, cluster, registry, type);
}
- protected <T> ClusterInvoker<T> getServiceDiscoveryInvoker(Cluster cluster, Class<T> type, URL url) {
- Registry registry = registryFactory.getRegistry(super.getRegistryUrl(url));
- ClusterInvoker<T> serviceDiscoveryInvoker = null;
- // enable auto migration from interface address pool to instance address pool
- boolean autoMigration = url.getParameter(ENABLE_REGISTRY_DIRECTORY_AUTO_MIGRATION, false);
- if (autoMigration) {
- DynamicDirectory<T> serviceDiscoveryDirectory = super.createDirectory(type, url);
- serviceDiscoveryDirectory.setRegistry(registry);
- serviceDiscoveryDirectory.setProtocol(protocol);
- Map<String, String> parameters = new HashMap<String, String>(serviceDiscoveryDirectory.getConsumerUrl().getParameters());
- URL urlToRegistry = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);
- if (serviceDiscoveryDirectory.isShouldRegister()) {
- serviceDiscoveryDirectory.setRegisteredConsumerUrl(urlToRegistry);
- registry.register(serviceDiscoveryDirectory.getRegisteredConsumerUrl());
- }
- serviceDiscoveryDirectory.buildRouterChain(urlToRegistry);
- serviceDiscoveryDirectory.subscribe(toSubscribeUrl(urlToRegistry));
- serviceDiscoveryInvoker = (ClusterInvoker<T>) cluster.join(serviceDiscoveryDirectory);
- }
- return serviceDiscoveryInvoker;
- }
-
- private static class MigrationInvoker<T> implements ClusterInvoker<T> {
- private ClusterInvoker<T> invoker;
- private ClusterInvoker<T> serviceDiscoveryInvoker;
-
- public MigrationInvoker(ClusterInvoker<T> invoker, ClusterInvoker<T> serviceDiscoveryInvoker) {
- this.invoker = invoker;
- this.serviceDiscoveryInvoker = serviceDiscoveryInvoker;
- }
-
- public ClusterInvoker<T> getInvoker() {
- return invoker;
- }
-
- public void setInvoker(ClusterInvoker<T> invoker) {
- this.invoker = invoker;
- }
-
- public ClusterInvoker<T> getServiceDiscoveryInvoker() {
- return serviceDiscoveryInvoker;
- }
-
- public void setServiceDiscoveryInvoker(ClusterInvoker<T> serviceDiscoveryInvoker) {
- this.serviceDiscoveryInvoker = serviceDiscoveryInvoker;
- }
-
- @Override
- public Class<T> getInterface() {
- return invoker.getInterface();
- }
-
- @Override
- public Result invoke(Invocation invocation) throws RpcException {
- if (serviceDiscoveryInvoker == null) {
- return invoker.invoke(invocation);
- }
-
- if (invoker.isDestroyed()) {
- return serviceDiscoveryInvoker.invoke(invocation);
- }
- if (serviceDiscoveryInvoker.isAvailable()) {
- invoker.destroy(); // can be destroyed asynchronously
- return serviceDiscoveryInvoker.invoke(invocation);
- }
- return invoker.invoke(invocation);
- }
-
- @Override
- public URL getUrl() {
- return invoker.getUrl();
- }
-
- @Override
- public boolean isAvailable() {
- if (serviceDiscoveryInvoker == null) {
- return invoker.isAvailable();
- }
- return invoker.isAvailable() || serviceDiscoveryInvoker.isAvailable();
- }
-
- @Override
- public void destroy() {
- if (invoker != null) {
- invoker.destroy();
- }
- if (serviceDiscoveryInvoker != null) {
- serviceDiscoveryInvoker.destroy();
- }
- }
-
- @Override
- public URL getRegistryUrl() {
- return invoker.getRegistryUrl();
- }
-
- @Override
- public Directory<T> getDirectory() {
- return invoker.getDirectory();
- }
-
- @Override
- public boolean isDestroyed() {
- if (serviceDiscoveryInvoker == null) {
- return invoker.isDestroyed();
- }
- return invoker.isDestroyed() && serviceDiscoveryInvoker.isDestroyed();
- }
+ protected <T> ClusterInvoker<T> getMigrationInvoker(RegistryProtocol registryProtocol, Cluster cluster, Registry registry, Class<T> type, URL url, URL consumerUrl) {
+// ClusterInvoker<T> invoker = getInvoker(cluster, registry, type, url);
+ return new MigrationInvoker<T>(registryProtocol, cluster, registry, type, url, consumerUrl);
}
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/InvokersChangedListener.java
similarity index 87%
rename from dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java
rename to dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/InvokersChangedListener.java
index 2042277..5a55a02 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/ConfigurationURL.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/InvokersChangedListener.java
@@ -14,7 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.common;
+package org.apache.dubbo.registry.integration;
-public class ConfigurationURL extends URL {
+public interface InvokersChangedListener {
+ void onChange();
}
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 b8d0b2d..4c65c6a 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
@@ -38,7 +38,6 @@
import org.apache.dubbo.rpc.cluster.Router;
import org.apache.dubbo.rpc.cluster.RouterChain;
import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
-import org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository;
import org.apache.dubbo.rpc.cluster.support.ClusterUtils;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.protocol.InvokerWrapper;
@@ -87,6 +86,12 @@
private static final ConsumerConfigurationListener CONSUMER_CONFIGURATION_LISTENER = new ConsumerConfigurationListener();
private ReferenceConfigurationListener referenceConfigurationListener;
+ // Map<url, Invoker> cache service url to invoker mapping.
+ // The initial value is null and the midway may be assigned to null, please use the local variable reference
+ protected volatile Map<URL, Invoker<T>> urlInvokerMap;
+ // The initial value is null and the midway may be assigned to null, please use the local variable reference
+ protected volatile Set<URL> cachedInvokerUrls;
+
public RegistryDirectory(Class<T> serviceType, URL url) {
super(serviceType, url);
}
@@ -94,7 +99,6 @@
@Override
public void subscribe(URL url) {
setConsumerUrl(url);
-// overrideConsumerUrl();
CONSUMER_CONFIGURATION_LISTENER.addNotifyListener(this);
referenceConfigurationListener = new ReferenceConfigurationListener(this, url);
registry.subscribe(url, this);
@@ -109,38 +113,6 @@
}
@Override
- public void destroy() {
- if (isDestroyed()) {
- return;
- }
-
- // unregister.
- try {
- if (getRegisteredConsumerUrl() != null && registry != null && registry.isAvailable()) {
- registry.unregister(getRegisteredConsumerUrl());
- }
- } catch (Throwable t) {
- logger.warn("unexpected error when unregister service " + serviceKey + "from registry" + registry.getUrl(), t);
- }
- // unsubscribe.
- try {
- if (getConsumerUrl() != null && registry != null && registry.isAvailable()) {
- registry.unsubscribe(getConsumerUrl(), this);
- }
- ExtensionLoader.getExtensionLoader(GovernanceRuleRepository.class).getDefaultExtension()
- .removeListener(ApplicationModel.getApplication(), CONSUMER_CONFIGURATION_LISTENER);
- } catch (Throwable t) {
- logger.warn("unexpected error when unsubscribe service " + serviceKey + "from registry" + registry.getUrl(), t);
- }
- super.destroy(); // must be executed after unsubscribing
- try {
- destroyAllInvokers();
- } catch (Throwable t) {
- logger.warn("Failed to destroy service " + serviceKey, t);
- }
- }
-
- @Override
public synchronized void notify(List<URL> urls) {
Map<String, List<URL>> categoryUrls = urls.stream()
.filter(Objects::nonNull)
@@ -182,7 +154,7 @@
private void refreshOverrideAndInvoker(List<URL> urls) {
// mock zookeeper://xxx?mock=return null
- overrideConsumerUrl();
+ overrideDirectoryUrl();
refreshInvoker(urls);
}
@@ -252,6 +224,9 @@
logger.warn("destroyUnusedInvokers error. ", e);
}
}
+
+ // notify invokers refreshed
+ this.invokersChanged();
}
private List<Invoker<T>> toMergeInvokerList(List<Invoker<T>> invokers) {
@@ -388,16 +363,19 @@
* @return
*/
private URL mergeUrl(URL providerUrl) {
- providerUrl = ClusterUtils.mergeProviderUrl(providerUrl, queryMap); // Merge the consumer side parameters
+ providerUrl = ClusterUtils.mergeUrl(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
+
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 = getConsumerUrl().getParameter(INTERFACE_KEY);
+ String path = directoryUrl.getParameter(INTERFACE_KEY);
if (path != null) {
int i = path.indexOf('/');
if (i >= 0) {
@@ -440,7 +418,8 @@
/**
* Close all invokers
*/
- private void destroyAllInvokers() {
+ @Override
+ protected void destroyAllInvokers() {
Map<URL, Invoker<T>> localUrlInvokerMap = this.urlInvokerMap; // local reference
if (localUrlInvokerMap != null) {
for (Invoker<T> invoker : new ArrayList<>(localUrlInvokerMap.values())) {
@@ -453,6 +432,7 @@
localUrlInvokerMap.clear();
}
invokers = null;
+ cachedInvokerUrls = null;
}
/**
@@ -535,6 +515,11 @@
return invokers;
}
+ @Override
+ public URL getConsumerUrl() {
+ return this.overrideDirectoryUrl;
+ }
+
public URL getRegisteredConsumerUrl() {
return registeredConsumerUrl;
}
@@ -597,25 +582,23 @@
return StringUtils.isEmpty(url.getParameter(COMPATIBLE_CONFIG_KEY));
}
- private void overrideConsumerUrl() {
+ private void overrideDirectoryUrl() {
// merge override parameters
- this.overrideConsumerUrl = getConsumerUrl();
- if (overrideConsumerUrl != null) {
- List<Configurator> localConfigurators = this.configurators; // local reference
- doOverrideUrl(localConfigurators);
- List<Configurator> localAppDynamicConfigurators = CONSUMER_CONFIGURATION_LISTENER.getConfigurators(); // local reference
- doOverrideUrl(localAppDynamicConfigurators);
- if (referenceConfigurationListener != null) {
- List<Configurator> localDynamicConfigurators = referenceConfigurationListener.getConfigurators(); // local reference
- doOverrideUrl(localDynamicConfigurators);
- }
+ this.overrideDirectoryUrl = directoryUrl;
+ List<Configurator> localConfigurators = this.configurators; // local reference
+ doOverrideUrl(localConfigurators);
+ List<Configurator> localAppDynamicConfigurators = CONSUMER_CONFIGURATION_LISTENER.getConfigurators(); // local reference
+ doOverrideUrl(localAppDynamicConfigurators);
+ if (referenceConfigurationListener != null) {
+ List<Configurator> localDynamicConfigurators = referenceConfigurationListener.getConfigurators(); // local reference
+ doOverrideUrl(localDynamicConfigurators);
}
}
private void doOverrideUrl(List<Configurator> configurators) {
if (CollectionUtils.isNotEmpty(configurators)) {
for (Configurator configurator : configurators) {
- this.overrideConsumerUrl = configurator.configure(overrideConsumerUrl);
+ this.overrideDirectoryUrl = configurator.configure(overrideDirectoryUrl);
}
}
}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/RegistryProtocol.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
similarity index 93%
rename from dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/RegistryProtocol.java
rename to dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
index 64ffe04..1f5a6c2 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/RegistryProtocol.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.registry.client;
+package org.apache.dubbo.registry.integration;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.config.ConfigurationUtils;
@@ -31,10 +31,8 @@
import org.apache.dubbo.registry.Registry;
import org.apache.dubbo.registry.RegistryFactory;
import org.apache.dubbo.registry.RegistryService;
-import org.apache.dubbo.registry.integration.AbstractConfiguratorListener;
-import org.apache.dubbo.registry.integration.DynamicDirectory;
-import org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol;
-import org.apache.dubbo.registry.integration.RegistryProtocolListener;
+import org.apache.dubbo.registry.client.ServiceDiscoveryRegistryDirectory;
+import org.apache.dubbo.registry.client.migration.ServiceDiscoveryMigrationInvoker;
import org.apache.dubbo.registry.retry.ReExportTask;
import org.apache.dubbo.registry.support.SkipFailbackWrapperException;
import org.apache.dubbo.rpc.Exporter;
@@ -48,6 +46,7 @@
import org.apache.dubbo.rpc.cluster.Configurator;
import org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository;
import org.apache.dubbo.rpc.cluster.support.MergeableCluster;
+import org.apache.dubbo.rpc.cluster.support.migration.MigrationClusterInvoker;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ProviderModel;
import org.apache.dubbo.rpc.protocol.InvokerWrapper;
@@ -444,32 +443,48 @@
String group = qs.get(GROUP_KEY);
if (group != null && group.length() > 0) {
if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) {
- return doRefer(Cluster.getCluster(MergeableCluster.NAME), registry, type, url);
+ return doRefer(Cluster.getCluster(MergeableCluster.NAME), registry, type, url, qs);
}
}
Cluster cluster = Cluster.getCluster(qs.get(CLUSTER_KEY));
- return doRefer(cluster, registry, type, url);
+ return doRefer(cluster, registry, type, url, qs);
}
- protected <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
- return interceptInvoker(getInvoker(cluster, registry, type, url), url);
+ protected <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url, Map<String, String> parameters) {
+ URL consumerUrl = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);
+ ClusterInvoker<T> migrationInvoker = getMigrationInvoker(this, cluster, registry, type, url, consumerUrl);
+ return interceptInvoker(migrationInvoker, url, consumerUrl);
}
- protected <T> Invoker<T> interceptInvoker(ClusterInvoker<T> invoker, URL url) {
+ protected <T> ClusterInvoker<T> getMigrationInvoker(RegistryProtocol registryProtocol, Cluster cluster, Registry registry, Class<T> type, URL url, URL consumerUrl) {
+ return new ServiceDiscoveryMigrationInvoker<T>(registryProtocol, cluster, registry, type, url, consumerUrl);
+ }
+
+ protected <T> Invoker<T> interceptInvoker(ClusterInvoker<T> invoker, URL url, URL consumerUrl) {
List<RegistryProtocolListener> listeners = findRegistryProtocolListeners(url);
if (CollectionUtils.isEmpty(listeners)) {
return invoker;
}
for (RegistryProtocolListener listener : listeners) {
- listener.onRefer(this, invoker);
+ listener.onRefer(this, invoker, consumerUrl);
}
return invoker;
}
- protected <T> ClusterInvoker<T> getInvoker(Cluster cluster, Registry registry, Class<T> type, URL url) {
- DynamicDirectory<T> directory = createDirectory(type, url);
+ public <T> ClusterInvoker<T> getServiceDiscoveryInvoker(Cluster cluster, Registry registry, Class<T> type, URL url) {
+ DynamicDirectory<T> directory = new ServiceDiscoveryRegistryDirectory<>(type, url);
+ return doCreateInvoker(directory, cluster, registry, type);
+ }
+
+ public <T> ClusterInvoker<T> getInvoker(Cluster cluster, Registry registry, Class<T> type, URL url) {
+ // FIXME, this method is currently not used, create the right registry before enable.
+ DynamicDirectory<T> directory = new RegistryDirectory<>(type, url);
+ return doCreateInvoker(directory, cluster, registry, type);
+ }
+
+ protected <T> ClusterInvoker<T> doCreateInvoker(DynamicDirectory<T> directory, Cluster cluster, Registry registry, Class<T> type) {
directory.setRegistry(registry);
directory.setProtocol(protocol);
// all attributes of REFER_KEY
@@ -485,23 +500,17 @@
return (ClusterInvoker<T>) cluster.join(directory);
}
- protected <T> DynamicDirectory<T> createDirectory(Class<T> type, URL url) {
- return new ServiceDiscoveryRegistryDirectory<>(type, url);
+ public <T> void reRefer(ClusterInvoker<?> invoker, URL newSubscribeUrl) {
+ if (!(invoker instanceof MigrationClusterInvoker)) {
+ logger.error("Only invoker type of MigrationClusterInvoker supports reRefer, current invoker is " + invoker.getClass());
+ return;
+ }
+
+ MigrationClusterInvoker<?> migrationClusterInvoker = (MigrationClusterInvoker<?>)invoker;
+ migrationClusterInvoker.reRefer(newSubscribeUrl);
}
- public <T> void reRefer(DynamicDirectory<T> directory, URL newSubscribeUrl) {
- URL oldSubscribeUrl = directory.getRegisteredConsumerUrl();
- Registry registry = directory.getRegistry();
- registry.unregister(directory.getRegisteredConsumerUrl());
- directory.unSubscribe(toSubscribeUrl(oldSubscribeUrl));
- registry.register(directory.getRegisteredConsumerUrl());
-
- directory.setRegisteredConsumerUrl(newSubscribeUrl);
- directory.buildRouterChain(newSubscribeUrl);
- directory.subscribe(toSubscribeUrl(newSubscribeUrl));
- }
-
- protected static URL toSubscribeUrl(URL url) {
+ public static URL toSubscribeUrl(URL url) {
return url.addParameter(CATEGORY_KEY, PROVIDERS_CATEGORY + "," + CONFIGURATORS_CATEGORY + "," + ROUTERS_CATEGORY);
}
@@ -529,7 +538,7 @@
}
}
- List<Exporter<?>> exporters = new ArrayList<>(bounds.values());
+ List<Exporter<?>> exporters = new ArrayList<Exporter<?>>(bounds.values());
for (Exporter<?> exporter : exporters) {
exporter.unexport();
}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocolListener.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocolListener.java
index 5bf47ca..c4cade5 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocolListener.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocolListener.java
@@ -18,9 +18,8 @@
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.SPI;
-import org.apache.dubbo.registry.client.RegistryProtocol;
import org.apache.dubbo.rpc.Exporter;
-import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.cluster.ClusterInvoker;
/**
* RegistryProtocol listener is introduced to provide a chance to user to customize or change export and refer behavior
@@ -42,9 +41,10 @@
*
* @param registryProtocol RegistryProtocol instance
* @param invoker invoker
+ * @param url
* @see RegistryProtocol#refer(Class, URL)
*/
- void onRefer(RegistryProtocol registryProtocol, Invoker<?> invoker);
+ void onRefer(RegistryProtocol registryProtocol, ClusterInvoker<?> invoker, URL url);
/**
* Notify RegistryProtocol's listeners when the protocol is destroyed
diff --git a/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.migration.MigrationAddressComparator b/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.migration.MigrationAddressComparator
new file mode 100644
index 0000000..b7fa71c
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.migration.MigrationAddressComparator
@@ -0,0 +1 @@
+default=org.apache.dubbo.registry.client.migration.DefaultMigrationAddressComparator
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.integration.RegistryProtocolListener b/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.integration.RegistryProtocolListener
index d60633c..24943f7 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.integration.RegistryProtocolListener
+++ b/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.integration.RegistryProtocolListener
@@ -1 +1 @@
-service-discovery=org.apache.dubbo.registry.client.ServiceDiscoveryRegistryProtocolListener
\ No newline at end of file
+migration=org.apache.dubbo.registry.client.migration.MigrationRuleListener
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol b/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol
index 5dda00e..4c3b148 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol
+++ b/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol
@@ -1,2 +1,2 @@
registry=org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol
-service-discovery-registry=org.apache.dubbo.registry.client.RegistryProtocol
\ No newline at end of file
+service-discovery-registry=org.apache.dubbo.registry.integration.RegistryProtocol
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java
index 6e71ae6..86ff3a2 100644
--- a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java
+++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java
@@ -58,8 +58,8 @@
}
}, executor);
- tesConditionRule();
-
+ testMigrationRule();
+// tesConditionRule();
// testStartupConfig();
// testProviderConfig();
// testPathCache();
@@ -68,6 +68,22 @@
// Thread.sleep(100000);
}
+ public static void testMigrationRule() {
+ String serviceStr = "---\n" +
+ "key: demo-consumer\n" +
+ "step: INTERFACE_FIRST\n" +
+ "...";
+ try {
+ String servicePath = "/dubbo/config/DUBBO_SERVICEDISCOVERY_MIGRATION/demo-consumer.migration";
+ if (client.checkExists().forPath(servicePath) == null) {
+ client.create().creatingParentsIfNeeded().forPath(servicePath);
+ }
+ setData(servicePath, serviceStr);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
public static void testStartupConfig() {
String str = "dubbo.registry.address=zookeeper://127.0.0.1:2181\n" +
"dubbo.registry.group=dubboregistrygroup1\n" +
diff --git a/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscovery.java b/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscovery.java
index 8b0f322..47474f4 100644
--- a/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscovery.java
+++ b/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscovery.java
@@ -88,7 +88,7 @@
private ExecutorService notifierExecutor = newCachedThreadPool(
new NamedThreadFactory("dubbo-service-discovery-consul-notifier", true));
private Map<String, ConsulNotifier> notifiers = new ConcurrentHashMap<>();
- private Map<String, TtlScheduler> ttlSchedulers = new ConcurrentHashMap<>();
+ private TtlScheduler ttlScheduler;
private long checkPassInterval;
private URL url;
@@ -123,6 +123,7 @@
int port = url.getPort() != 0 ? url.getPort() : DEFAULT_PORT;
checkPassInterval = url.getParameter(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL);
client = new ConsulClient(host, port);
+ ttlScheduler = new TtlScheduler(checkPassInterval, client);
this.tag = registryURL.getParameter(QUERY_TAG);
this.registeringTags.addAll(getRegisteringTags(url));
this.aclToken = ACL_TOKEN.getValue(registryURL);
@@ -176,23 +177,18 @@
@Override
public void destroy() {
- if (!notifiers.isEmpty()) {
- notifiers.forEach((key, notifier) -> notifier.stop());
- notifiers.clear();
- }
-
+ notifiers.forEach((_k, notifier) -> {
+ if (notifier != null) {
+ notifier.stop();
+ }
+ });
+ notifiers.clear();
notifierExecutor.shutdownNow();
-
- if (!ttlSchedulers.isEmpty()) {
- ttlSchedulers.forEach((key, ttlScheduler) -> ttlScheduler.stop());
- ttlSchedulers.clear();
- }
+ ttlScheduler.stop();
}
@Override
public void register(ServiceInstance serviceInstance) throws RuntimeException {
- super.register(serviceInstance);
- TtlScheduler ttlScheduler = ttlSchedulers.computeIfAbsent(serviceInstance.getServiceName(), name -> new TtlScheduler(checkPassInterval, client));
NewService consulService = buildService(serviceInstance);
ttlScheduler.add(consulService.getId());
client.agentServiceRegister(consulService, aclToken);
@@ -200,14 +196,13 @@
@Override
public void addServiceInstancesChangedListener(ServiceInstancesChangedListener listener) throws NullPointerException, IllegalArgumentException {
- for (String serviceName : listener.getServiceNames()) {
+ Set<String> serviceNames = listener.getServiceNames();
+ for (String serviceName : serviceNames) {
ConsulNotifier notifier = notifiers.get(serviceName);
-
if (notifier == null) {
Response<List<HealthService>> response = getHealthServices(serviceName, -1, buildWatchTimeout());
Long consulIndex = response.getConsulIndex();
notifier = new ConsulNotifier(serviceName, consulIndex);
- notifiers.put(serviceName, notifier);
}
notifierExecutor.execute(notifier);
}
@@ -215,18 +210,14 @@
@Override
public void update(ServiceInstance serviceInstance) throws RuntimeException {
- super.update(serviceInstance);
// TODO
// client.catalogRegister(buildCatalogService(serviceInstance));
}
@Override
public void unregister(ServiceInstance serviceInstance) throws RuntimeException {
- TtlScheduler ttlScheduler = ttlSchedulers.get(serviceInstance.getServiceName());
String id = buildId(serviceInstance);
- if (ttlScheduler != null) {
- ttlScheduler.remove(id);
- }
+ ttlScheduler.remove(id);
client.agentServiceDeregister(id, aclToken);
}
@@ -243,7 +234,6 @@
public List<ServiceInstance> getInstances(String serviceName) throws NullPointerException {
Response<List<HealthService>> response = getHealthServices(serviceName, -1, buildWatchTimeout());
Long consulIndex = response.getConsulIndex();
-
ConsulNotifier notifier = notifiers.get(serviceName);
if (notifier == null) {
notifier = new ConsulNotifier(serviceName, consulIndex);
diff --git a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java b/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscoveryFactory.java~HEAD
similarity index 74%
rename from dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java
rename to dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscoveryFactory.java~HEAD
index 7bef1f5..bd77db8 100644
--- a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java
+++ b/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscoveryFactory.java~HEAD
@@ -14,15 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.registry.multicast;
+package org.apache.dubbo.registry.consul;
import org.apache.dubbo.common.URL;
+import org.apache.dubbo.registry.client.AbstractServiceDiscoveryFactory;
import org.apache.dubbo.registry.client.ServiceDiscovery;
-import org.apache.dubbo.registry.client.ServiceDiscoveryFactory;
-public class MulticastServiceDiscoveryFactory implements ServiceDiscoveryFactory {
+public class ConsulServiceDiscoveryFactory extends AbstractServiceDiscoveryFactory {
+
@Override
- public ServiceDiscovery getServiceDiscovery(URL registryURL) {
- return new MulticastServiceDiscovery();
+ protected ServiceDiscovery createDiscovery(URL registryURL) {
+ return new ConsulServiceDiscovery();
}
+
}
diff --git a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java b/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscoveryFactory.java~dubbo-master
similarity index 74%
copy from dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java
copy to dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscoveryFactory.java~dubbo-master
index 7bef1f5..bd77db8 100644
--- a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java
+++ b/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscoveryFactory.java~dubbo-master
@@ -14,15 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.registry.multicast;
+package org.apache.dubbo.registry.consul;
import org.apache.dubbo.common.URL;
+import org.apache.dubbo.registry.client.AbstractServiceDiscoveryFactory;
import org.apache.dubbo.registry.client.ServiceDiscovery;
-import org.apache.dubbo.registry.client.ServiceDiscoveryFactory;
-public class MulticastServiceDiscoveryFactory implements ServiceDiscoveryFactory {
+public class ConsulServiceDiscoveryFactory extends AbstractServiceDiscoveryFactory {
+
@Override
- public ServiceDiscovery getServiceDiscovery(URL registryURL) {
- return new MulticastServiceDiscovery();
+ protected ServiceDiscovery createDiscovery(URL registryURL) {
+ return new ConsulServiceDiscovery();
}
+
}
diff --git a/dubbo-registry/dubbo-registry-consul/src/test/java/org/apache/dubbo/registry/consul/ConsulServiceDiscoveryTest.java b/dubbo-registry/dubbo-registry-consul/src/test/java/org/apache/dubbo/registry/consul/ConsulServiceDiscoveryTest.java
index 9f10d0a..2b6f526 100644
--- a/dubbo-registry/dubbo-registry-consul/src/test/java/org/apache/dubbo/registry/consul/ConsulServiceDiscoveryTest.java
+++ b/dubbo-registry/dubbo-registry-consul/src/test/java/org/apache/dubbo/registry/consul/ConsulServiceDiscoveryTest.java
@@ -26,6 +26,7 @@
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
@@ -35,6 +36,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
+@Disabled
public class ConsulServiceDiscoveryTest {
private URL url;
diff --git a/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryDirectoryTest.java b/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryDirectoryTest.java
index 9ddf3b0..bb1f925 100644
--- a/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryDirectoryTest.java
+++ b/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryDirectoryTest.java
@@ -58,7 +58,9 @@
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.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.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
@@ -68,6 +70,7 @@
import static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.ROUTE_PROTOCOL;
import static org.apache.dubbo.registry.Constants.CONSUMER_PROTOCOL;
+import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
import static org.apache.dubbo.rpc.Constants.MOCK_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.INVOCATION_NEED_MOCK;
import static org.apache.dubbo.rpc.cluster.Constants.MOCK_PROTOCOL;
@@ -144,13 +147,17 @@
@Test
public void test_Constructor_CheckStatus() throws Exception {
URL url = URL.valueOf("notsupported://10.20.30.40/" + service + "?a=b").addParameterAndEncoded(REFER_KEY,
- "foo=bar");
+ "foo=bar&" + REGISTER_IP_KEY + "=10.20.30.40&" + INTERFACE_KEY + "=" + service);
RegistryDirectory reg = getRegistryDirectory(url);
Field field = reg.getClass().getSuperclass().getSuperclass().getDeclaredField("queryMap");
field.setAccessible(true);
Map<String, String> queryMap = (Map<String, String>) field.get(reg);
Assertions.assertEquals("bar", queryMap.get("foo"));
- Assertions.assertEquals(url.setProtocol(CONSUMER_PROTOCOL).clearParameters().addParameter("foo", "bar"), reg.getConsumerUrl());
+ URL expected = url.setProtocol(DUBBO_PROTOCOL).clearParameters()
+ .addParameter("foo", "bar")
+ .addParameter(REGISTER_IP_KEY, "10.20.30.40")
+ .addParameter(INTERFACE_KEY, service);
+ Assertions.assertEquals(expected, reg.getConsumerUrl());
}
@Test
diff --git a/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryProtocolTest.java b/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryProtocolTest.java
index 596a217..aedf313 100644
--- a/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryProtocolTest.java
+++ b/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryProtocolTest.java
@@ -19,10 +19,12 @@
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.registry.NotifyListener;
import org.apache.dubbo.registry.RegistryFactory;
import org.apache.dubbo.registry.RegistryService;
-import org.apache.dubbo.registry.client.RegistryProtocol;
+import org.apache.dubbo.registry.integration.RegistryProtocol;
import org.apache.dubbo.registry.support.AbstractRegistry;
import org.apache.dubbo.remoting.exchange.ExchangeClient;
import org.apache.dubbo.rpc.Exporter;
@@ -37,6 +39,7 @@
import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;
import org.apache.commons.lang3.ArrayUtils;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -44,7 +47,7 @@
import java.util.ArrayList;
import java.util.List;
-import static org.apache.dubbo.registry.client.RegistryProtocol.DEFAULT_REGISTER_PROVIDER_KEYS;
+import static org.apache.dubbo.registry.integration.RegistryProtocol.DEFAULT_REGISTER_PROVIDER_KEYS;
import static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -61,7 +64,7 @@
}
final String service = DemoService.class.getName() + ":1.0.0";
- final String serviceUrl = "dubbo://127.0.0.1:9453/" + service + "?notify=true&methods=test1,test2&side=con&side=consumer";
+ final String serviceUrl = "dubbo://127.0.0.1:9453/" + service + "?notify=true&methods=test1,test2&side=con&side=consumer®ister.ip=127.0.0.1";
final URL registryUrl = URL.valueOf("registry://127.0.0.1:9090/");
final private Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
@@ -72,9 +75,18 @@
@BeforeEach
public void setUp() {
ApplicationModel.setApplication("RegistryProtocolTest");
+ ConfigManager configManager = ApplicationModel.getConfigManager();
+ ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-demo-provider");
+ configManager.setApplication(applicationConfig);
ApplicationModel.getServiceRepository().registerService(RegistryService.class);
}
+ @AfterEach
+ public void reset() {
+ ApplicationModel.getConfigManager().destroy();
+ }
+
+
@Test
public void testDefaultPort() {
RegistryProtocol registryProtocol = getRegistryProtocol();
diff --git a/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryStatusCheckerTest.java b/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryStatusCheckerTest.java
index 62dcad1..d8ae08a 100644
--- a/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryStatusCheckerTest.java
+++ b/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryStatusCheckerTest.java
@@ -64,7 +64,7 @@
assertEquals(Status.Level.OK, new RegistryStatusChecker().check().getLevel());
String message = new RegistryStatusChecker().check().getMessage();
- Assertions.assertTrue(message.contains(registryUrl.getAddress() + "(connected)"));
- Assertions.assertTrue(message.contains(registryUrl2.getAddress() + "(connected)"));
+ Assertions.assertTrue(message.contains(registryUrl.getHost() + "(connected)"));
+ Assertions.assertTrue(message.contains(registryUrl2.getHost() + "(connected)"));
}
}
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-etcd3/src/main/java/org/apache/dubbo/registry/etcd/EtcdServiceDiscovery.java b/dubbo-registry/dubbo-registry-etcd3/src/main/java/org/apache/dubbo/registry/etcd/EtcdServiceDiscovery.java
index 4bcdb59..39e5818 100644
--- a/dubbo-registry/dubbo-registry-etcd3/src/main/java/org/apache/dubbo/registry/etcd/EtcdServiceDiscovery.java
+++ b/dubbo-registry/dubbo-registry-etcd3/src/main/java/org/apache/dubbo/registry/etcd/EtcdServiceDiscovery.java
@@ -102,7 +102,6 @@
@Override
public void register(ServiceInstance serviceInstance) throws RuntimeException {
- super.register(serviceInstance);
try {
this.serviceInstance = serviceInstance;
String path = toPath(serviceInstance);
@@ -128,7 +127,6 @@
@Override
public void update(ServiceInstance serviceInstance) throws RuntimeException {
- super.register(serviceInstance);
try {
String path = toPath(serviceInstance);
etcdClient.putEphemeral(path, new Gson().toJson(serviceInstance));
diff --git a/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistry.java b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistry.java
index 8ad2c10..2e4ca35 100644
--- a/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistry.java
+++ b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistry.java
@@ -118,7 +118,7 @@
@Override
public boolean isAvailable() {
- boolean available = serviceRegistries.isEmpty() ? true : false;
+ boolean available = serviceRegistries.isEmpty();
for (Registry serviceRegistry : serviceRegistries.values()) {
if (serviceRegistry.isAvailable()) {
available = true;
@@ -128,7 +128,7 @@
return false;
}
- available = referenceRegistries.isEmpty() ? true : false;
+ available = referenceRegistries.isEmpty();
for (Registry referenceRegistry : referenceRegistries.values()) {
if (referenceRegistry.isAvailable()) {
available = true;
diff --git a/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistryServiceDiscovery.java b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistryServiceDiscovery.java
new file mode 100644
index 0000000..0302c9a
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistryServiceDiscovery.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 MultipleRegistryServiceDiscovery 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-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistryServiceDiscoveryFactory.java
similarity index 73%
copy from dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java
copy to dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistryServiceDiscoveryFactory.java
index 7bef1f5..37d7de2 100644
--- a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java
+++ b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistryServiceDiscoveryFactory.java
@@ -14,15 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.registry.multicast;
+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;
-import org.apache.dubbo.registry.client.ServiceDiscoveryFactory;
-public class MulticastServiceDiscoveryFactory implements ServiceDiscoveryFactory {
+public class MultipleRegistryServiceDiscoveryFactory extends AbstractServiceDiscoveryFactory {
@Override
- public ServiceDiscovery getServiceDiscovery(URL registryURL) {
- return new MulticastServiceDiscovery();
+ protected ServiceDiscovery createDiscovery(URL registryURL) {
+ return new MultipleRegistryServiceDiscovery();
}
}
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..95e2d98
--- /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.MultipleRegistryServiceDiscovery
\ 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..710a207
--- /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.MultipleRegistryServiceDiscoveryFactory
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceDiscovery.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceDiscovery.java
index 19b0026..a1067f7 100644
--- a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceDiscovery.java
+++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceDiscovery.java
@@ -81,10 +81,13 @@
@Override
public void update(ServiceInstance serviceInstance) throws RuntimeException {
- super.update(serviceInstance);
// TODO: Nacos should support
- unregister(serviceInstance);
- register(serviceInstance);
+ if (this.serviceInstance == null) {
+ register(serviceInstance);
+ } else {
+ unregister(serviceInstance);
+ register(serviceInstance);
+ }
}
@Override
@@ -136,11 +139,6 @@
return registryURL;
}
- @Override
- public ServiceInstance getLocalInstance() {
- return null;
- }
-
private void handleEvent(NamingEvent event, ServiceInstancesChangedListener listener) {
String serviceName = event.getServiceName();
List<ServiceInstance> serviceInstances = event.getInstances()
diff --git a/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryServiceDiscovery.java b/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryServiceDiscovery.java
index 77e7441..86a7dc3 100644
--- a/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryServiceDiscovery.java
+++ b/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryServiceDiscovery.java
@@ -16,6 +16,17 @@
*/
package org.apache.dubbo.registry.sofa;
+import com.alipay.sofa.registry.client.api.Publisher;
+import com.alipay.sofa.registry.client.api.RegistryClientConfig;
+import com.alipay.sofa.registry.client.api.Subscriber;
+import com.alipay.sofa.registry.client.api.model.RegistryType;
+import com.alipay.sofa.registry.client.api.model.UserData;
+import com.alipay.sofa.registry.client.api.registration.PublisherRegistration;
+import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration;
+import com.alipay.sofa.registry.client.provider.DefaultRegistryClient;
+import com.alipay.sofa.registry.client.provider.DefaultRegistryClientConfigBuilder;
+import com.alipay.sofa.registry.core.model.ScopeEnum;
+import com.google.gson.Gson;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
@@ -29,18 +40,6 @@
import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;
import org.apache.dubbo.rpc.RpcException;
-import com.alipay.sofa.registry.client.api.Publisher;
-import com.alipay.sofa.registry.client.api.RegistryClientConfig;
-import com.alipay.sofa.registry.client.api.Subscriber;
-import com.alipay.sofa.registry.client.api.model.RegistryType;
-import com.alipay.sofa.registry.client.api.model.UserData;
-import com.alipay.sofa.registry.client.api.registration.PublisherRegistration;
-import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration;
-import com.alipay.sofa.registry.client.provider.DefaultRegistryClient;
-import com.alipay.sofa.registry.client.provider.DefaultRegistryClientConfigBuilder;
-import com.alipay.sofa.registry.core.model.ScopeEnum;
-import com.google.gson.Gson;
-
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -53,6 +52,7 @@
import static org.apache.dubbo.registry.sofa.SofaRegistryConstants.LOCAL_DATA_CENTER;
import static org.apache.dubbo.registry.sofa.SofaRegistryConstants.LOCAL_REGION;
+
public class SofaRegistryServiceDiscovery implements ServiceDiscovery {
private static final Logger LOGGER = LoggerFactory.getLogger(SofaRegistryServiceDiscovery.class);
diff --git a/dubbo-registry/dubbo-registry-sofa/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory b/dubbo-registry/dubbo-registry-sofa/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory
new file mode 100644
index 0000000..d16d75c
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-sofa/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory
@@ -0,0 +1 @@
+sofa=org.apache.dubbo.registry.sofa.SofaRegistryServiceDiscoveryFactory
\ No newline at end of file
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 a4cdd6c..a1277da 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
@@ -23,7 +23,7 @@
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;
@@ -51,26 +51,22 @@
* 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 implements ServiceDiscovery {
+public class ZookeeperServiceDiscovery extends AbstractServiceDiscovery {
private final Logger logger = LoggerFactory.getLogger(getClass());
private URL registryURL;
- private EventDispatcher dispatcher;
-
private CuratorFramework curatorFramework;
private String rootPath;
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}
*/
- private final Map<String, CuratorWatcher> watcherCaches = new ConcurrentHashMap<>();
+ private final Map<String, ZookeeperServiceDiscoveryChangeWatcher> watcherCaches = new ConcurrentHashMap<>();
@Override
public void initialize(URL registryURL) throws Exception {
@@ -90,20 +86,13 @@
serviceDiscovery.close();
}
- @Override
- public ServiceInstance getLocalInstance() {
- return serviceInstance;
- }
-
public void register(ServiceInstance serviceInstance) throws RuntimeException {
- this.serviceInstance = serviceInstance;
doInServiceRegistry(serviceDiscovery -> {
serviceDiscovery.registerService(build(serviceInstance));
});
}
public void update(ServiceInstance serviceInstance) throws RuntimeException {
- this.serviceInstance = serviceInstance;
if (isInstanceUpdated(serviceInstance)) {
doInServiceRegistry(serviceDiscovery -> {
serviceDiscovery.updateService(build(serviceInstance));
@@ -135,25 +124,30 @@
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);
@@ -166,6 +160,14 @@
listener.getServiceNames().forEach(serviceName -> registerServiceWatcher(serviceName, listener));
}
+ @Override
+ public void removeServiceInstancesChangedListener(ServiceInstancesChangedListener listener) throws IllegalArgumentException {
+ listener.getServiceNames().forEach(serviceName -> {
+ ZookeeperServiceDiscoveryChangeWatcher watcher = watcherCaches.remove(serviceName);
+ watcher.stopWatching();
+ });
+ }
+
private void doInServiceRegistry(ThrowableConsumer<org.apache.curator.x.discovery.ServiceDiscovery> consumer) {
ThrowableConsumer.execute(serviceDiscovery, s -> {
consumer.accept(s);
@@ -178,6 +180,17 @@
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/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryChangeWatcher.java b/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryChangeWatcher.java
index 5ee429a..1e8f171 100644
--- a/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryChangeWatcher.java
+++ b/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryChangeWatcher.java
@@ -39,6 +39,8 @@
private final ZookeeperServiceDiscovery zookeeperServiceDiscovery;
+ private boolean keepWatching = true;
+
private final String serviceName;
public ZookeeperServiceDiscoveryChangeWatcher(ZookeeperServiceDiscovery zookeeperServiceDiscovery,
@@ -55,9 +57,19 @@
Watcher.Event.EventType eventType = event.getType();
if (NodeChildrenChanged.equals(eventType) || NodeDataChanged.equals(eventType)) {
- listener.onEvent(new ServiceInstancesChangedEvent(serviceName, zookeeperServiceDiscovery.getInstances(serviceName)));
- zookeeperServiceDiscovery.registerServiceWatcher(serviceName, listener);
- zookeeperServiceDiscovery.dispatchServiceInstancesChangedEvent(serviceName);
+ if (shouldKeepWatching()) {
+ listener.onEvent(new ServiceInstancesChangedEvent(serviceName, zookeeperServiceDiscovery.getInstances(serviceName)));
+ zookeeperServiceDiscovery.registerServiceWatcher(serviceName, listener);
+ zookeeperServiceDiscovery.dispatchServiceInstancesChangedEvent(serviceName);
+ }
}
}
+
+ public boolean shouldKeepWatching() {
+ return keepWatching;
+ }
+
+ public void stopWatching() {
+ this.keepWatching = false;
+ }
}
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-registry/dubbo-registry-zookeeper/src/test/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryTest.java b/dubbo-registry/dubbo-registry-zookeeper/src/test/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryTest.java
index 0a30a0a..f04a5b5 100644
--- a/dubbo-registry/dubbo-registry-zookeeper/src/test/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryTest.java
+++ b/dubbo-registry/dubbo-registry-zookeeper/src/test/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryTest.java
@@ -85,7 +85,7 @@
assertEquals(asList(serviceInstance), serviceInstances);
Map<String, String> metadata = new HashMap<>();
- metadata.put("message", "Hello,World");
+ //metadata.put("message", "Hello,World");
serviceInstance.setMetadata(metadata);
discovery.update(serviceInstance);
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/TelnetUtils.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/TelnetUtils.java
index 50a06c9..219ca04 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/TelnetUtils.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/TelnetUtils.java
@@ -115,7 +115,7 @@
buf.append("\r\n");
//content
for (List<String> row : table) {
- StringBuffer rowbuf = new StringBuffer();
+ StringBuilder rowbuf = new StringBuilder();
rowbuf.append("|");
for (int j = 0; j < widths.length; j++) {
String cell = row.get(j);
@@ -125,7 +125,7 @@
if (rowbuf.length() >= totalWidth) {
buf.append(rowbuf.toString());
- rowbuf = new StringBuffer();
+ rowbuf = new StringBuilder();
// for(int m = 0;m < maxcountbefore && maxcountbefore < totalWidth ; m++){
// rowbuf.append(" ");
// }
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/LogTelnetHandler.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/LogTelnetHandler.java
index 2d39c23..6c0167d 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/LogTelnetHandler.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/LogTelnetHandler.java
@@ -44,7 +44,7 @@
public String telnet(Channel channel, String message) {
long size = 0;
File file = LoggerFactory.getFile();
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
if (message == null || message.trim().length() == 0) {
buf.append("EXAMPLE: log error / log 100");
} else {
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java
index a4d59cc..68ee081 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java
@@ -22,7 +22,6 @@
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.ExecutorUtil;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.ChannelHandler;
@@ -38,6 +37,7 @@
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_CLIENT_THREADPOOL;
import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;
/**
* AbstractClient
@@ -48,6 +48,7 @@
private static final Logger logger = LoggerFactory.getLogger(AbstractClient.class);
private final Lock connectLock = new ReentrantLock();
private final boolean needReconnect;
+ //issue-7054:Consumer's executor is sharing globally.
protected volatile ExecutorService executor;
private ExecutorRepository executorRepository = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
@@ -90,7 +91,8 @@
}
private void initExecutor(URL url) {
- url = ExecutorUtil.setThreadName(url, CLIENT_THREAD_POOL_NAME);
+ //issue-7054:Consumer's executor is sharing globally, thread name not require provider ip.
+ url = url.addParameter(THREAD_NAME_KEY, CLIENT_THREAD_POOL_NAME);
url = url.addParameterIfAbsent(THREADPOOL_KEY, DEFAULT_CLIENT_THREADPOOL);
executor = executorRepository.createExecutorIfAbsent(url);
}
@@ -278,14 +280,6 @@
}
try {
- if (executor != null) {
- ExecutorUtil.shutdownNow(executor, 100);
- }
- } catch (Throwable e) {
- logger.warn(e.getMessage(), e);
- }
-
- try {
disconnect();
} catch (Throwable e) {
logger.warn(e.getMessage(), e);
@@ -304,7 +298,6 @@
@Override
public void close(int timeout) {
- ExecutorUtil.gracefulShutdown(executor, timeout);
close();
}
diff --git a/dubbo-remoting/dubbo-remoting-etcd3/src/main/java/org/apache/dubbo/remoting/etcd/jetcd/JEtcdClientWrapper.java b/dubbo-remoting/dubbo-remoting-etcd3/src/main/java/org/apache/dubbo/remoting/etcd/jetcd/JEtcdClientWrapper.java
index d6c5733..0de6703 100644
--- a/dubbo-remoting/dubbo-remoting-etcd3/src/main/java/org/apache/dubbo/remoting/etcd/jetcd/JEtcdClientWrapper.java
+++ b/dubbo-remoting/dubbo-remoting-etcd3/src/main/java/org/apache/dubbo/remoting/etcd/jetcd/JEtcdClientWrapper.java
@@ -17,6 +17,7 @@
package org.apache.dubbo.remoting.etcd.jetcd;
+import java.nio.charset.StandardCharsets;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
@@ -112,7 +113,7 @@
private volatile boolean cancelKeepAlive = false;
- public static final Charset UTF_8 = Charset.forName("UTF-8");
+ public static final Charset UTF_8 = StandardCharsets.UTF_8;
public JEtcdClientWrapper(URL url) {
this.url = url;
diff --git a/dubbo-remoting/dubbo-remoting-grizzly/src/main/java/org/apache/dubbo/remoting/transport/grizzly/GrizzlyCodecAdapter.java b/dubbo-remoting/dubbo-remoting-grizzly/src/main/java/org/apache/dubbo/remoting/transport/grizzly/GrizzlyCodecAdapter.java
index 39e6990..c720fd5 100644
--- a/dubbo-remoting/dubbo-remoting-grizzly/src/main/java/org/apache/dubbo/remoting/transport/grizzly/GrizzlyCodecAdapter.java
+++ b/dubbo-remoting/dubbo-remoting-grizzly/src/main/java/org/apache/dubbo/remoting/transport/grizzly/GrizzlyCodecAdapter.java
@@ -128,10 +128,8 @@
}
if (msg != null) {
context.setMessage(msg);
- return context.getInvokeAction();
- } else {
- return context.getInvokeAction();
}
+ return context.getInvokeAction();
}
} while (frame.readable());
} else { // Other events are passed down directly
diff --git a/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/transport/netty/ThreadNameTest.java b/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/transport/netty/ThreadNameTest.java
index 001b56a..3783d02 100644
--- a/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/transport/netty/ThreadNameTest.java
+++ b/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/transport/netty/ThreadNameTest.java
@@ -39,7 +39,7 @@
private ThreadNameVerifyHandler clientHandler;
private static String serverRegex = "DubboServerHandler\\-localhost:(\\d+)\\-thread\\-(\\d+)";
- private static String clientRegex = "DubboClientHandler\\-localhost:(\\d+)\\-thread\\-(\\d+)";
+ private static String clientRegex = "DubboClientHandler\\-thread\\-(\\d+)";
@BeforeEach
public void before() throws Exception {
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 @@
String getContent(String path);
+ boolean checkExists(String path);
+
}
diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java
index 625f001..34679c3 100644
--- a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java
+++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java
@@ -16,6 +16,7 @@
*/
package org.apache.dubbo.remoting.zookeeper.curator;
+import java.nio.charset.StandardCharsets;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
@@ -54,7 +55,7 @@
protected static final Logger logger = LoggerFactory.getLogger(CuratorZookeeperClient.class);
private static final String ZK_SESSION_EXPIRE_KEY = "zk.session.expire";
- static final Charset CHARSET = Charset.forName("UTF-8");
+ static final Charset CHARSET = StandardCharsets.UTF_8;
private final CuratorFramework client;
private Map<String, TreeCache> treeCacheMap = new ConcurrentHashMap<>();
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 @@
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-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AppResponse.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AppResponse.java
index 22538ac..118e701 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AppResponse.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AppResponse.java
@@ -16,7 +16,8 @@
*/
package org.apache.dubbo.rpc;
-import java.lang.reflect.Field;
+import org.apache.dubbo.rpc.proxy.InvokerInvocationHandler;
+
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@@ -34,7 +35,7 @@
* <li>AsyncRpcResult is the object that is actually passed in the call chain</li>
* <li>AppResponse only simply represents the business result</li>
* </ul>
- *
+ * <p>
* The relationship between them can be described as follow, an abstraction of the definition of AsyncRpcResult:
* <pre>
* {@code
@@ -79,15 +80,7 @@
if (exception != null) {
// fix issue#619
try {
- // get Throwable class
- Class clazz = exception.getClass();
- while (!clazz.getName().equals(Throwable.class.getName())) {
- clazz = clazz.getSuperclass();
- }
- // get stackTrace value
- Field stackTraceField = clazz.getDeclaredField("stackTrace");
- stackTraceField.setAccessible(true);
- Object stackTrace = stackTraceField.get(exception);
+ Object stackTrace = InvokerInvocationHandler.stackTraceField.get(exception);
if (stackTrace == null) {
exception.setStackTrace(new StackTraceElement[0]);
}
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..2c451c6 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.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;
/**
@@ -103,7 +101,8 @@
try {
String accessLogKey = invoker.getUrl().getParameter(ACCESS_LOG_KEY);
if (ConfigUtils.isNotEmpty(accessLogKey)) {
- AccessLogData logData = buildAccessLogData(invoker, inv);
+ AccessLogData logData = AccessLogData.newLogData();
+ logData.buildAccessLogData(invoker, inv);
log(accessLogKey, logData);
}
} catch (Throwable t) {
@@ -166,18 +165,6 @@
}
}
- private AccessLogData buildAccessLogData(Invoker<?> invoker, Invocation inv) {
- 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.setInvocationTime(new Date());
- logData.setTypes(inv.getParameterTypes());
- logData.setArguments(inv.getArguments());
- return logData;
- }
-
private void processWithServiceLogger(Set<AccessLogData> logSet) {
for (Iterator<AccessLogData> iterator = logSet.iterator();
iterator.hasNext();
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/GenericImplFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/GenericImplFilter.java
index 20ef2ce..f841f3f 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/GenericImplFilter.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/GenericImplFilter.java
@@ -107,7 +107,7 @@
if (ProtocolUtils.isJavaGenericSerialization(generic)) {
for (Object arg : args) {
- if (!(byte[].class == arg.getClass())) {
+ if (byte[].class != arg.getClass()) {
error(generic, byte[].class.getName(), arg.getClass().getName());
}
}
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/FilterNode.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/FilterNode.java
new file mode 100644
index 0000000..00da913
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/FilterNode.java
@@ -0,0 +1,117 @@
+/*
+ * 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.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.Result;
+import org.apache.dubbo.rpc.RpcException;
+
+/**
+ * @see org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper
+ *
+ */
+class FilterNode<T> implements Invoker<T>{
+ private final Invoker<T> invoker;
+ private final Invoker<T> next;
+ private final Filter filter;
+
+ public FilterNode(final Invoker<T> invoker, final Invoker<T> next, final Filter filter) {
+ this.invoker = invoker;
+ this.next = next;
+ this.filter = filter;
+ }
+
+ @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();
+ }
+
+}
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..aa17b40 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
@@ -23,12 +23,9 @@
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;
@@ -56,86 +53,8 @@
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();
- }
- };
+ for (Filter filter : filters) {
+ last = new FilterNode<T>(invoker, last, filter);
}
}
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyFactory.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyFactory.java
index 837750f..8698fe6 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyFactory.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyFactory.java
@@ -60,7 +60,7 @@
}
if (generic) {
- if (!GenericService.class.isAssignableFrom(invoker.getInterface())) {
+ if (GenericService.class.equals(invoker.getInterface()) || !GenericService.class.isAssignableFrom(invoker.getInterface())) {
interfaces.add(com.alibaba.dubbo.rpc.service.GenericService.class);
}
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/InvokerInvocationHandler.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/InvokerInvocationHandler.java
index 69f1d06..6e43c52 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/InvokerInvocationHandler.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/InvokerInvocationHandler.java
@@ -26,6 +26,7 @@
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ConsumerModel;
+import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
@@ -39,6 +40,17 @@
private URL url;
private String protocolServiceKey;
+ public static Field stackTraceField;
+
+ static {
+ try {
+ stackTraceField = Throwable.class.getDeclaredField("stackTrace");
+ stackTraceField.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ // ignore
+ }
+ }
+
public InvokerInvocationHandler(Invoker<?> handler) {
this.invoker = handler;
this.url = invoker.getUrl();
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/AccessLogData.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/AccessLogData.java
index e9ff358..ca2eac2 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/AccessLogData.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/AccessLogData.java
@@ -17,10 +17,15 @@
package org.apache.dubbo.rpc.support;
import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcContext;
import com.alibaba.fastjson.JSON;
+import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
+
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@@ -262,5 +267,15 @@
private void set(String key, Object value) {
data.put(key, value);
}
+
+ public void buildAccessLogData(Invoker<?> invoker, Invocation inv) {
+ setServiceName(invoker.getInterface().getName());
+ setMethodName(inv.getMethodName());
+ setVersion(invoker.getUrl().getParameter(VERSION_KEY));
+ setGroup(invoker.getUrl().getParameter(GROUP_KEY));
+ setInvocationTime(new Date());
+ setTypes(inv.getParameterTypes());
+ setArguments(inv.getArguments());
+ }
}
diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java
index 380b2c3..3c7b495 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java
@@ -139,6 +139,7 @@
map.keySet().forEach(context::remove);
Assertions.assertNull(context.get("_11"));
+ RpcContext.removeContext();
}
@Test
diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/AccessLogFilterTest.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/AccessLogFilterTest.java
index 5bfcb4b..d02971c 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/AccessLogFilterTest.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/AccessLogFilterTest.java
@@ -17,6 +17,7 @@
package org.apache.dubbo.rpc.filter;
import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.DubboAppender;
import org.apache.dubbo.common.utils.LogUtil;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation;
@@ -51,6 +52,7 @@
accessLogFilter.invoke(invoker, invocation);
assertEquals(1, LogUtil.findMessage("Exception in AccessLogFilter of service"));
LogUtil.stop();
+ DubboAppender.clear();
}
// TODO how to assert thread action
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 5085f58..3b87068 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
@@ -296,8 +296,8 @@
}
return inObject;
}
- byte callBackStatus = isCallBack(url, inv.getProtocolServiceKey(), inv.getMethodName(), paraIndex);
- switch (callBackStatus) {
+ byte callbackstatus = isCallBack(url, inv.getProtocolServiceKey(), inv.getMethodName(), paraIndex);
+ switch (callbackstatus) {
case CallbackServiceCodec.CALLBACK_CREATE:
try {
return referOrDestroyCallbackService(channel, url, pts[paraIndex], inv, Integer.parseInt(inv.getAttachment(INV_ATT_CALLBACK_KEY + paraIndex)), true);
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 a794863..74115be 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
@@ -389,11 +389,9 @@
} catch (ClassNotFoundException e) {
throw new RpcException("Cannot find the serialization optimizer class: " + className, e);
- } catch (InstantiationException e) {
+ } catch (InstantiationException | IllegalAccessException e) {
throw new RpcException("Cannot instantiate the serialization optimizer class: " + className, e);
- } catch (IllegalAccessException e) {
- throw new RpcException("Cannot instantiate the serialization optimizer class: " + className, e);
}
}
diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvokerAvilableTest.java b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvokerAvilableTest.java
index d2c318b..6eaaf86 100644
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvokerAvilableTest.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvokerAvilableTest.java
@@ -90,6 +90,7 @@
}
@Disabled
+ @Test
public void test_normal_channel_close_wait_gracefully() throws Exception {
int testPort = NetUtils.getAvailablePort();
URL url = URL.valueOf("dubbo://127.0.0.1:" + testPort + "/org.apache.dubbo.rpc.protocol.dubbo.IDemoService?scope=true&lazy=false");
diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocolTest.java b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocolTest.java
index e432dbd..b1eeff9 100644
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocolTest.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocolTest.java
@@ -37,6 +37,7 @@
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
@@ -94,7 +95,7 @@
service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?client=netty").addParameter("timeout",
3000L)));
// test netty client
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
for (int i = 0; i < 1024 * 32 + 32; i++)
buf.append('A');
System.out.println(service.stringLength(buf.toString()));
@@ -108,6 +109,7 @@
assertEquals(echo.$echo(1234), 1234);
}
+ @Disabled("Mina has been moved to a separate project")
@Test
public void testDubboProtocolWithMina() throws Exception {
DemoService service = new DemoServiceImpl();
@@ -132,7 +134,7 @@
service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?client=mina").addParameter("timeout",
3000L)));
// test netty client
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
for (int i = 0; i < 1024 * 32 + 32; i++)
buf.append('A');
System.out.println(service.stringLength(buf.toString()));
diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/decode/DubboTelnetDecodeTest.java b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/decode/DubboTelnetDecodeTest.java
index 3c66d75..c0ffd8a 100644
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/decode/DubboTelnetDecodeTest.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/decode/DubboTelnetDecodeTest.java
@@ -42,6 +42,7 @@
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.IOException;
@@ -261,7 +262,8 @@
*
* @throws InterruptedException
*/
- // @Test
+ @Disabled
+ @Test
public void testTelnetTelnetDecoded() throws InterruptedException {
ByteBuf firstByteBuf = Unpooled.wrappedBuffer("ls\r".getBytes());
ByteBuf secondByteBuf = Unpooled.wrappedBuffer("\nls\r\n".getBytes());
diff --git a/dubbo-rpc/dubbo-rpc-native-thrift/src/test/java/org/apache/dubbo/rpc/protocol/nativethrift/DemoService.java b/dubbo-rpc/dubbo-rpc-native-thrift/src/test/java/org/apache/dubbo/rpc/protocol/nativethrift/DemoService.java
index 97572f1..7e1de88 100644
--- a/dubbo-rpc/dubbo-rpc-native-thrift/src/test/java/org/apache/dubbo/rpc/protocol/nativethrift/DemoService.java
+++ b/dubbo-rpc/dubbo-rpc-native-thrift/src/test/java/org/apache/dubbo/rpc/protocol/nativethrift/DemoService.java
@@ -3680,8 +3680,6 @@
public boolean equals(timeOut_result that) {
if (that == null)
return false;
- if (this == that)
- return true;
return true;
}
@@ -3930,8 +3928,6 @@
public boolean equals(customException_args that) {
if (that == null)
return false;
- if (this == that)
- return true;
return true;
}
diff --git a/dubbo-rpc/dubbo-rpc-redis/src/main/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocol.java b/dubbo-rpc/dubbo-rpc-redis/src/main/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocol.java
index b508188..67dcd7b 100644
--- a/dubbo-rpc/dubbo-rpc-redis/src/main/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocol.java
+++ b/dubbo-rpc/dubbo-rpc-redis/src/main/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocol.java
@@ -43,7 +43,6 @@
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.Map;
-import java.util.concurrent.TimeoutException;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
@@ -150,7 +149,7 @@
}
} catch (Throwable t) {
RpcException re = new RpcException("Failed to invoke redis service method. interface: " + type.getName() + ", method: " + invocation.getMethodName() + ", url: " + url + ", cause: " + t.getMessage(), t);
- if (t instanceof TimeoutException || t instanceof SocketTimeoutException) {
+ if (t instanceof SocketTimeoutException) {
re.setCode(RpcException.TIMEOUT_EXCEPTION);
} else if (t instanceof JedisConnectionException || t instanceof IOException) {
re.setCode(RpcException.NETWORK_EXCEPTION);
diff --git a/dubbo-rpc/dubbo-rpc-thrift/src/test/java/$__ClassNameTestDubboStub.java b/dubbo-rpc/dubbo-rpc-thrift/src/test/java/$__ClassNameTestDubboStub.java
index c7f92d7..348f151 100644
--- a/dubbo-rpc/dubbo-rpc-thrift/src/test/java/$__ClassNameTestDubboStub.java
+++ b/dubbo-rpc/dubbo-rpc-thrift/src/test/java/$__ClassNameTestDubboStub.java
@@ -35,7 +35,7 @@
public interface Iface {
- public String echo(String arg);
+ String echo(String arg);
}
diff --git a/dubbo-rpc/dubbo-rpc-webservice/src/test/java/org/apache/dubbo/rpc/protocol/webservice/WebserviceProtocolTest.java b/dubbo-rpc/dubbo-rpc-webservice/src/test/java/org/apache/dubbo/rpc/protocol/webservice/WebserviceProtocolTest.java
index da18ba4..e3d15eb 100644
--- a/dubbo-rpc/dubbo-rpc-webservice/src/test/java/org/apache/dubbo/rpc/protocol/webservice/WebserviceProtocolTest.java
+++ b/dubbo-rpc/dubbo-rpc-webservice/src/test/java/org/apache/dubbo/rpc/protocol/webservice/WebserviceProtocolTest.java
@@ -69,7 +69,7 @@
System.out.println(object);
assertEquals("webservice://127.0.0.1:" + port + "/org.apache.dubbo.rpc.protocol.webservice.DemoService:invoke", object);
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
for (int i = 0; i < 1024 * 32 + 32; i++)
buf.append('A');
assertEquals(32800, service.stringLength(buf.toString()));
diff --git a/pom.xml b/pom.xml
index efbb9ca..5040ebc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -126,7 +126,7 @@
<arguments />
<checkstyle.skip>true</checkstyle.skip>
<rat.skip>true</rat.skip>
- <revision>2.7.9</revision>
+ <revision>2.7.10-SNAPSHOT</revision>
</properties>
<modules>