You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2018/09/14 09:31:26 UTC
[incubator-dubbo] branch dev-metadata updated: Merge pull request
#2468,
Simplify registry data and add a new service data store seperated from
registry #2030 (#2468)
This is an automated email from the ASF dual-hosted git repository.
liujun pushed a commit to branch dev-metadata
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo.git
The following commit(s) were added to refs/heads/dev-metadata by this push:
new 577eb77 Merge pull request #2468, Simplify registry data and add a new service data store seperated from registry #2030 (#2468)
577eb77 is described below
commit 577eb77cce6cd0e52fe581e406f7d9b2e9a34a7c
Author: cvictory <sh...@gmail.com>
AuthorDate: Fri Sep 14 17:31:18 2018 +0800
Merge pull request #2468, Simplify registry data and add a new service data store seperated from registry #2030 (#2468)
---
dubbo-bom/pom.xml | 15 ++
.../apache/dubbo/rpc/cluster/RouterFactory.java | 2 +-
.../java/org/apache/dubbo/common/Constants.java | 15 ++
.../src/main/java/org/apache/dubbo/common/URL.java | 43 +++-
dubbo-config/dubbo-config-api/pom.xml | 7 +-
.../dubbo/config/AbstractInterfaceConfig.java | 66 ++++-
.../org/apache/dubbo/config/ReferenceConfig.java | 10 +
.../org/apache/dubbo/config/RegistryConfig.java | 30 ++-
.../org/apache/dubbo/config/ServiceConfig.java | 11 +
.../apache/dubbo/config/ServiceStoreConfig.java | 94 +++++++
.../apache/dubbo/config/spring/ReferenceBean.java | 10 +
.../apache/dubbo/config/spring/ServiceBean.java | 10 +
.../spring/schema/DubboNamespaceHandler.java | 2 +
.../src/main/resources/META-INF/compat/dubbo.xsd | 54 +++-
.../src/main/resources/META-INF/dubbo.xsd | 47 ++++
dubbo-demo/dubbo-demo-consumer/pom.xml | 6 +-
.../META-INF/spring/dubbo-demo-consumer.xml | 6 +-
dubbo-demo/dubbo-demo-provider/pom.xml | 10 +-
.../META-INF/spring/dubbo-demo-provider.xml | 82 +++---
dubbo-registry/dubbo-registry-api/pom.xml | 2 +-
.../registry/integration/RegistryProtocol.java | 71 ++++--
dubbo-servicedata/dubbo-servicedata-api/pom.xml | 41 +++
.../org/apache/dubbo/servicedata/ServiceStore.java | 92 +++----
.../dubbo/servicedata/ServiceStoreFactory.java | 82 +++---
.../integration/ServiceStoreService.java | 81 ++++++
.../servicedata/support/AbstractServiceStore.java | 279 +++++++++++++++++++++
.../support/AbstractServiceStoreFactory.java | 80 ++++++
.../integration/ServiceStoreServiceTest.java | 7 +
.../support/AbstractServiceStoreFactoryTest.java | 72 ++++++
.../support/AbstractServiceStoreTest.java | 110 ++++++++
dubbo-servicedata/dubbo-servicedata-redis/pom.xml | 34 +++
.../dubbo/servicedata/redis/RedisServiceStore.java | 73 ++++++
.../redis/RedisServiceStoreFactory.java | 36 +++
...rg.apache.dubbo.servicedata.ServiceStoreFactory | 1 +
.../dubbo-servicedata-zookeeper/pom.xml | 31 +++
.../zookeeper/ZookeeperServiceStore.java | 132 ++++++++++
.../zookeeper/ZookeeperServiceStoreFactory.java | 41 +++
...rg.apache.dubbo.servicedata.ServiceStoreFactory | 1 +
dubbo-servicedata/pom.xml | 21 ++
pom.xml | 1 +
40 files changed, 1639 insertions(+), 169 deletions(-)
diff --git a/dubbo-bom/pom.xml b/dubbo-bom/pom.xml
index a1d8277..ad64f3f 100644
--- a/dubbo-bom/pom.xml
+++ b/dubbo-bom/pom.xml
@@ -293,6 +293,21 @@
<artifactId>dubbo-compatible</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-servicedata-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-servicedata-zookeeper</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-servicedata-redis</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java
index 4d35c78..bf32cad 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java
@@ -49,4 +49,4 @@ public interface RouterFactory {
default Router getRouter(DynamicConfiguration dynamicConfiguration, URL url) {
return null;
}
-}
\ No newline at end of file
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java
index 0e82118..49b0bd1 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java
@@ -84,6 +84,8 @@ public class Constants {
public static final String REGISTRY_PROTOCOL = "registry";
+ public static final String SERVICE_STORE_PROTOCOL = "servicestore";
+
public static final String $INVOKE = "$invoke";
public static final String $ECHO = "$echo";
@@ -178,6 +180,8 @@ public class Constants {
public static final String REGISTRY_KEY = "registry";
+ public static final String SERVICE_STORE_KEY = "servicestore";
+
public static final String MONITOR_KEY = "monitor";
public static final String SIDE_KEY = "side";
@@ -435,6 +439,17 @@ public class Constants {
public static final String MERGER_KEY = "merger";
/**
+ * simple the registry.
+ * @since 2.7.0
+ */
+ public static final String SIMPLE_KEY = "simple";
+ /**
+ * After simplify the registry, should add some paramter individually.
+ * @since 2.7.0
+ */
+ public static final String ADD_PARAM_KEYS_KEY = "addParamKeys";
+
+ /**
* To decide whether to exclude unavailable invoker from the cluster
*/
public static final String CLUSTER_AVAILABLE_CHECK_KEY = "cluster.availablecheck";
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 a83ca91..312b691 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
@@ -187,7 +187,7 @@ public /**final**/ class URL implements Serializable {
int port = 0;
String path = null;
Map<String, String> parameters = null;
- int i = url.indexOf("?"); // seperator between body and parameters
+ int i = url.indexOf("?"); // seperator between body and parameters
if (i >= 0) {
String[] parts = url.substring(i + 1).split("\\&");
parameters = new HashMap<String, String>();
@@ -250,6 +250,47 @@ public /**final**/ class URL implements Serializable {
return new URL(protocol, username, password, host, port, path, parameters);
}
+ public static URL valueOf(String url, String... reserveParams){
+ URL result = valueOf(url);
+ if (reserveParams == null || reserveParams.length == 0){
+ return result;
+ }
+ Map<String, String> newMap = new HashMap<String,String>(reserveParams.length);
+ Map<String, String> oldMap = result.getParameters();
+ for(String reserveParam : reserveParams){
+ String tmp = oldMap.get(reserveParam);
+ if(StringUtils.isNotEmpty(tmp)){
+ newMap.put(reserveParam, tmp);
+ }
+ }
+ return result.clearParameters().addParameters(newMap);
+ }
+
+ public static URL valueOf(URL url, String[] reserveParams, String[] reserveParamPrefixs) {
+ Map<String, String> newMap = new HashMap<String, String>();
+ Map<String, String> oldMap = url.getParameters();
+ if (reserveParamPrefixs != null && reserveParamPrefixs.length != 0) {
+ for (Map.Entry<String, String> entry : oldMap.entrySet()) {
+ for (String reserveParamPrefix : reserveParamPrefixs){
+ if (entry.getKey().startsWith(reserveParamPrefix) && StringUtils.isNotEmpty(entry.getValue())){
+ newMap.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+ }
+
+ if (reserveParams != null) {
+ for (String reserveParam : reserveParams) {
+ String tmp = oldMap.get(reserveParam);
+ if (StringUtils.isNotEmpty(tmp)) {
+ newMap.put(reserveParam, tmp);
+ }
+ }
+ }
+
+ return newMap.isEmpty() ? url : url.clearParameters().addParameters(newMap);
+ }
+
public static String encode(String value) {
if (value == null || value.length() == 0) {
return "";
diff --git a/dubbo-config/dubbo-config-api/pom.xml b/dubbo-config/dubbo-config-api/pom.xml
index da0a287..7a2229c 100644
--- a/dubbo-config/dubbo-config-api/pom.xml
+++ b/dubbo-config/dubbo-config-api/pom.xml
@@ -36,6 +36,11 @@
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-servicedata-api</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-monitor-api</artifactId>
<version>${project.parent.version}</version>
</dependency>
@@ -123,4 +128,4 @@
<scope>test</scope>
</dependency>
</dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
index 70ab62e..0e4f93e 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
@@ -35,11 +35,14 @@ import org.apache.dubbo.rpc.InvokerListener;
import org.apache.dubbo.rpc.ProxyFactory;
import org.apache.dubbo.rpc.cluster.Cluster;
import org.apache.dubbo.rpc.support.MockInvoker;
+import org.apache.dubbo.servicedata.ServiceStoreFactory;
+import org.apache.dubbo.servicedata.integration.ServiceStoreService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.function.Supplier;
/**
* AbstractDefaultConfig
@@ -102,6 +105,9 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
// the scope for referring/exporting a service, if it's local, it means searching in current JVM only.
private String scope;
+ protected ServiceStoreConfig serviceStoreConfig;
+
+
protected void checkRegistry() {
// for backward compatibility
if (registries == null || registries.isEmpty()) {
@@ -255,6 +261,55 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
return null;
}
+ protected URL loadServiceStore(boolean provider) {
+ // FIXME
+ // checkRegistry();
+ if(serviceStoreConfig == null){
+ return null;
+ }
+ URL loadServiceUrl ;
+
+ String address = serviceStoreConfig.getAddress();
+ if (address == null || address.length() == 0) {
+ address = Constants.ANYHOST_VALUE;
+ }
+
+ if (address.length() > 0 && !RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
+ Map<String, String> map = new HashMap<String, String>();
+ appendParameters(map, application);
+ appendParameters(map, serviceStoreConfig);
+ map.put("path", ServiceStoreConfig.class.getName());
+ map.put("dubbo", Version.getProtocolVersion());
+ map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
+ if (ConfigUtils.getPid() > 0) {
+ map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
+ }
+ if (!map.containsKey("protocol")) {
+ if (ExtensionLoader.getExtensionLoader(ServiceStoreFactory.class).hasExtension("remote")) {
+ map.put("protocol", "remote");
+ } else {
+ map.put("protocol", "dubbo");
+ }
+ }
+ URL url = UrlUtils.parseURL(address, map);
+ url = url.addParameter(Constants.SERVICE_STORE_KEY, url.getProtocol()).setProtocol(Constants.SERVICE_STORE_PROTOCOL);
+ if ((provider && url.getParameter(Constants.REGISTER_KEY, true))
+ || (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) {
+ return url;
+ }
+ }
+ return null;
+ }
+
+ protected ServiceStoreService getServiceStoreService() {
+ if (serviceStoreConfig == null) {
+ return null;
+ }
+ return ServiceStoreService.instance(() -> {
+ return loadServiceStore(true);
+ });
+ }
+
protected void checkInterfaceAndMethods(Class<?> interfaceClass, List<MethodConfig> methods) {
// interface cannot be null
if (interfaceClass == null) {
@@ -522,4 +577,13 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
public void setScope(String scope) {
this.scope = scope;
}
-}
\ No newline at end of file
+
+ public ServiceStoreConfig getServiceStoreConfig() {
+ return serviceStoreConfig;
+ }
+
+ public void setServiceStoreConfig(ServiceStoreConfig serviceStoreConfig) {
+ this.serviceStoreConfig = serviceStoreConfig;
+ }
+
+}
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 1a82c6a..43e3ca0 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
@@ -41,6 +41,7 @@ import org.apache.dubbo.rpc.cluster.support.ClusterUtils;
import org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol;
import org.apache.dubbo.rpc.service.GenericService;
import org.apache.dubbo.rpc.support.ProtocolUtils;
+import org.apache.dubbo.servicedata.integration.ServiceStoreService;
import java.io.File;
import java.io.FileInputStream;
@@ -427,6 +428,15 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
if (logger.isInfoEnabled()) {
logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl());
}
+ /**
+ * @since 2.7.0
+ * ServiceData Store
+ */
+ ServiceStoreService serviceStoreService = null;
+ if ((serviceStoreService = getServiceStoreService()) != null){
+ URL consumerURL = new URL(Constants.CONSUMER_PROTOCOL, map.remove(Constants.REGISTER_IP_KEY), 0, map.get(Constants.INTERFACE_KEY), map);
+ serviceStoreService.publishConsumer(consumerURL);
+ }
// create service proxy
return (T) proxyFactory.getProxy(invoker);
}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
index a9a8145..5678a2e 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
@@ -19,6 +19,7 @@ package org.apache.dubbo.config;
import org.apache.dubbo.common.Constants;
import org.apache.dubbo.config.support.Parameter;
+import java.util.List;
import java.util.Map;
/**
@@ -88,6 +89,18 @@ public class RegistryConfig extends AbstractConfig {
// if it's default
private Boolean isDefault;
+ /**
+ * simple the registry.
+ * @since 2.7.0
+ */
+ private Boolean simple;
+ /**
+ * After simplify the registry, should add some paramter individually.
+ * addionalParameterKeys = addParamKeys
+ * @since 2.7.0
+ */
+ private String addParamKeys;
+
public RegistryConfig() {
}
@@ -321,4 +334,19 @@ public class RegistryConfig extends AbstractConfig {
this.isDefault = isDefault;
}
-}
\ No newline at end of file
+ public Boolean getSimple() {
+ return simple;
+ }
+
+ public void setSimple(Boolean simple) {
+ this.simple = simple;
+ }
+
+ public String getAddParamKeys() {
+ return addParamKeys;
+ }
+
+ public void setAddParamKeys(String addParamKeys) {
+ this.addParamKeys = addParamKeys;
+ }
+}
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 e9d5e6b..200cb34 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
@@ -38,6 +38,7 @@ import org.apache.dubbo.rpc.ServiceClassHolder;
import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
import org.apache.dubbo.rpc.service.GenericService;
import org.apache.dubbo.rpc.support.ProtocolUtils;
+import org.apache.dubbo.servicedata.integration.ServiceStoreService;
import java.lang.reflect.Method;
import java.net.InetAddress;
@@ -520,6 +521,16 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
+ /**
+ * @since 2.7.0
+ * ServiceData Store
+ */
+ ServiceStoreService serviceStoreService = null;
+ if ((serviceStoreService = getServiceStoreService()) != null){
+// String protocol = url.getProtocol();
+// url = url.setProtocol(Constants.PROVIDER_PROTOCOL).addParameter(Constants.SIDE_KEY, Constants.PROVIDER_SIDE).addParameter(Constants.PROTOCOL_KEY, protocol);
+ serviceStoreService.publishProvider(url);
+ }
}
}
this.urls.add(url);
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceStoreConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceStoreConfig.java
new file mode 100644
index 0000000..1a31c90
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceStoreConfig.java
@@ -0,0 +1,94 @@
+/*
+ * 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.config;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.config.support.Parameter;
+
+import java.util.Map;
+
+/**
+ * RegistryConfig
+ *
+ * @export
+ */
+public class ServiceStoreConfig extends AbstractConfig {
+
+ public static final String NO_AVAILABLE = "N/A";
+ private static final long serialVersionUID = 55233L;
+ // register center address
+ private String address;
+
+ // username to login register center
+ private String username;
+
+ // password to login register center
+ private String password;
+
+ // request timeout in milliseconds for register center
+ private Integer timeout;
+
+ // customized parameters
+ private Map<String, String> parameters;
+
+ public ServiceStoreConfig() {
+ }
+
+ public ServiceStoreConfig(String address) {
+ setAddress(address);
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public Integer getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(Integer timeout) {
+ this.timeout = timeout;
+ }
+
+ public Map<String, String> getParameters() {
+ return parameters;
+ }
+
+ public void setParameters(Map<String, String> parameters) {
+ this.parameters = parameters;
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ReferenceBean.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ReferenceBean.java
index e6a2a1f..2eb4475 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ReferenceBean.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ReferenceBean.java
@@ -22,6 +22,7 @@ import org.apache.dubbo.config.ModuleConfig;
import org.apache.dubbo.config.MonitorConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceStoreConfig;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.spring.extension.SpringExtensionFactory;
import org.apache.dubbo.config.support.Parameter;
@@ -149,6 +150,15 @@ public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean,
}
}
}
+ if (getServiceStoreConfig() == null) {
+ Map<String, ServiceStoreConfig> serviceStoreConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ServiceStoreConfig.class, false, false);
+ if (serviceStoreConfigMap != null && serviceStoreConfigMap.size() == 1) {
+ // first elements
+ super.setServiceStoreConfig(serviceStoreConfigMap.values().iterator().next());
+ } else if(serviceStoreConfigMap != null && serviceStoreConfigMap.size() > 1){
+ throw new IllegalStateException("Multiple ServiceStore configs: " + serviceStoreConfigMap);
+ }
+ }
if (getMonitor() == null
&& (getConsumer() == null || getConsumer().getMonitor() == null)
&& (getApplication() == null || getApplication().getMonitor() == null)) {
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java
index 5b41b24..ddf1608 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java
@@ -23,6 +23,7 @@ import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.ServiceStoreConfig;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.config.spring.extension.SpringExtensionFactory;
import org.springframework.aop.support.AopUtils;
@@ -219,6 +220,15 @@ public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean
}
}
}
+ if (getServiceStoreConfig() == null) {
+ Map<String, ServiceStoreConfig> serviceStoreConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ServiceStoreConfig.class, false, false);
+ if (serviceStoreConfigMap != null && serviceStoreConfigMap.size() == 1) {
+ // 第一个元素
+ super.setServiceStoreConfig(serviceStoreConfigMap.values().iterator().next());
+ } else if(serviceStoreConfigMap != null && serviceStoreConfigMap.size() > 1){
+ throw new IllegalStateException("Multiple ServiceStore configs: " + serviceStoreConfigMap);
+ }
+ }
if (getMonitor() == null
&& (getProvider() == null || getProvider().getMonitor() == null)
&& (getApplication() == null || getApplication().getMonitor() == null)) {
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandler.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandler.java
index 9f16c39..57701c6 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandler.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandler.java
@@ -24,6 +24,7 @@ import org.apache.dubbo.config.MonitorConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceStoreConfig;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.ServiceBean;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
@@ -44,6 +45,7 @@ public class DubboNamespaceHandler extends NamespaceHandlerSupport {
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
+ registerBeanDefinitionParser("servicestore", new DubboBeanDefinitionParser(ServiceStoreConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd
index 5924591..39ad36b 100644
--- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd
+++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd
@@ -550,6 +550,47 @@
<xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
+ <xsd:attribute name="simple" type="xsd:boolean">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ Is simple. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="addParamKeys" type="xsd:string">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ Addtional Parameter Keys. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+
+ <xsd:complexType name="serviceStoreType">
+ <xsd:sequence minOccurs="0" maxOccurs="unbounded">
+ <xsd:element ref="parameter" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:ID">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="address" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The servicestore address. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="username" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The servicestore username. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="password" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The servicestore password. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="timeout" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The request timeout. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
</xsd:complexType>
<xsd:complexType name="monitorType">
@@ -1211,6 +1252,17 @@
</xsd:annotation>
</xsd:element>
+ <xsd:element name="servicestore" type="servicestoreType">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The servicestore config ]]></xsd:documentation>
+ <xsd:appinfo>
+ <tool:annotation>
+ <tool:exports type="org.apache.dubbo.config.ServiceStoreConfig"/>
+ </tool:annotation>
+ </xsd:appinfo>
+ </xsd:annotation>
+ </xsd:element>
+
<xsd:element name="monitor" type="monitorType">
<xsd:annotation>
<xsd:documentation><![CDATA[ The logstat monitor config ]]></xsd:documentation>
@@ -1305,4 +1357,4 @@
</xsd:annotation>
</xsd:element>
-</xsd:schema>
\ No newline at end of file
+</xsd:schema>
diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
index ecec23a..6952666 100644
--- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
+++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
@@ -544,6 +544,47 @@
<xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
+ <xsd:attribute name="simple" type="xsd:boolean">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ Is simple. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="addParamKeys" type="xsd:string">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ Addtional Parameter Keys. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+
+ <xsd:complexType name="serviceStoreType">
+ <xsd:sequence minOccurs="0" maxOccurs="unbounded">
+ <xsd:element ref="parameter" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:ID">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="address" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The servicestore address. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="username" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The servicestore username. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="password" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The servicestore password. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="timeout" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The request timeout. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
</xsd:complexType>
<xsd:complexType name="monitorType">
@@ -1205,6 +1246,12 @@
</xsd:annotation>
</xsd:element>
+ <xsd:element name="servicestore" type="serviceStoreType">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The servicestore config ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+
<xsd:element name="monitor" type="monitorType">
<xsd:annotation>
<xsd:documentation><![CDATA[ The logstat monitor config ]]></xsd:documentation>
diff --git a/dubbo-demo/dubbo-demo-consumer/pom.xml b/dubbo-demo/dubbo-demo-consumer/pom.xml
index 91468c8..cc25019 100644
--- a/dubbo-demo/dubbo-demo-consumer/pom.xml
+++ b/dubbo-demo/dubbo-demo-consumer/pom.xml
@@ -62,5 +62,9 @@
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-config-dynamic</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-servicedata-zookeeper</artifactId>
+ </dependency>
</dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml
index 68494f5..86472c5 100644
--- a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml
+++ b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml
@@ -31,8 +31,10 @@
<!-- use multicast registry center to discover service -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
+ <dubbo:servicestore address="zookeeper://127.0.0.1:2181"/>
+
<!-- generate proxy for the remote service, then demoService can be used in the same way as the
local regular interface -->
- <dubbo:reference id="demoService" check="false" interface="org.apache.dubbo.demo.DemoService"/>
+ <dubbo:reference id="demoService" check="false" interface="org.apache.dubbo.demo.DemoService" version="1.0.2"/>
-</beans>
\ No newline at end of file
+</beans>
diff --git a/dubbo-demo/dubbo-demo-provider/pom.xml b/dubbo-demo/dubbo-demo-provider/pom.xml
index b9f46b1..8045fad 100644
--- a/dubbo-demo/dubbo-demo-provider/pom.xml
+++ b/dubbo-demo/dubbo-demo-provider/pom.xml
@@ -63,5 +63,13 @@
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-config-dynamic</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-servicedata-zookeeper</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-servicedata-redis</artifactId>
+ </dependency>
</dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml
index 96ebae1..7604b32 100644
--- a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml
+++ b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml
@@ -1,40 +1,42 @@
-<?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">
-
- <!-- provider's application name, used for tracing dependency relationship -->
- <dubbo:application name="demo-provider"/>
- <!--<dubbo:provider tag="tag3"/>-->
-
- <!-- use multicast registry center to export service -->
- <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
-
- <!-- use dubbo protocol to export service on port 20880 -->
- <dubbo:protocol name="dubbo" port="-1"/>
-
- <!-- service implementation, as same as regular local bean -->
- <bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>
-
- <!-- declare the service interface to be exported -->
- <dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService"/>
-
-</beans>
\ No newline at end of file
+<?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">
+
+ <!-- provider's application name, used for tracing dependency relationship -->
+ <dubbo:application name="demo-provider"/>
+ <!--<dubbo:provider tag="tag3"/>-->
+
+ <!-- use multicast registry center to export service -->
+ <dubbo:registry address="zookeeper://127.0.0.1:2181" simple="true" />
+
+ <dubbo:servicestore address="redis://127.0.0.1:6379"/>
+
+ <!-- use dubbo protocol to export service on port 20880 -->
+ <dubbo:protocol name="dubbo" port="-1"/>
+
+ <!-- service implementation, as same as regular local bean -->
+ <bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>
+
+ <!-- declare the service interface to be exported -->
+ <dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService" version="1.0.2"/>
+
+</beans>
diff --git a/dubbo-registry/dubbo-registry-api/pom.xml b/dubbo-registry/dubbo-registry-api/pom.xml
index c6494e4..88a5000 100644
--- a/dubbo-registry/dubbo-registry-api/pom.xml
+++ b/dubbo-registry/dubbo-registry-api/pom.xml
@@ -55,4 +55,4 @@
</exclusions>
</dependency>
</dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
index dc86b55..7c112e2 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
@@ -16,6 +16,7 @@
*/
package org.apache.dubbo.registry.integration;
+import org.apache.commons.lang.ArrayUtils;
import org.apache.dubbo.common.Constants;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
@@ -57,16 +58,34 @@ import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import static org.apache.dubbo.common.Constants.ACCEPT_FOREIGN_IP;
+import static org.apache.dubbo.common.Constants.ADD_PARAM_KEYS_KEY;
import static org.apache.dubbo.common.Constants.APPLICATION_KEY;
+import static org.apache.dubbo.common.Constants.CLUSTER_KEY;
+import static org.apache.dubbo.common.Constants.CODEC_KEY;
import static org.apache.dubbo.common.Constants.CONFIGURATORS_SUFFIX;
import static org.apache.dubbo.common.Constants.CONFIG_PROTOCOL;
+import static org.apache.dubbo.common.Constants.CONNECTIONS_KEY;
+import static org.apache.dubbo.common.Constants.DEPRECATED_KEY;
+import static org.apache.dubbo.common.Constants.EXCHANGER_KEY;
import static org.apache.dubbo.common.Constants.EXPORT_KEY;
+import static org.apache.dubbo.common.Constants.GROUP_KEY;
import static org.apache.dubbo.common.Constants.INTERFACES;
import static org.apache.dubbo.common.Constants.INTERFACE_KEY;
+import static org.apache.dubbo.common.Constants.LOADBALANCE_KEY;
+import static org.apache.dubbo.common.Constants.METHODS_KEY;
+import static org.apache.dubbo.common.Constants.MOCK_KEY;
+import static org.apache.dubbo.common.Constants.PATH_KEY;
import static org.apache.dubbo.common.Constants.QOS_ENABLE;
import static org.apache.dubbo.common.Constants.QOS_PORT;
import static org.apache.dubbo.common.Constants.REFER_KEY;
+import static org.apache.dubbo.common.Constants.SERIALIZATION_KEY;
+import static org.apache.dubbo.common.Constants.TIMEOUT_KEY;
+import static org.apache.dubbo.common.Constants.TIMESTAMP_KEY;
+import static org.apache.dubbo.common.Constants.TOKEN_KEY;
import static org.apache.dubbo.common.Constants.VALIDATION_KEY;
+import static org.apache.dubbo.common.Constants.VERSION_KEY;
+import static org.apache.dubbo.common.Constants.WARMUP_KEY;
+import static org.apache.dubbo.common.Constants.WEIGHT_KEY;
/**
* RegistryProtocol
@@ -162,7 +181,7 @@ public class RegistryProtocol implements Protocol {
// url to registry
final Registry registry = getRegistry(originInvoker);
- final URL registeredProviderUrl = getRegistedProviderUrl(providerUrl);
+ final URL registeredProviderUrl = getRegistedProviderUrl(providerUrl, registryUrl);
ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registeredProviderUrl);
@@ -280,18 +299,28 @@ public class RegistryProtocol implements Protocol {
* @param providerUrl
* @return url to registry.
*/
- private URL getRegistedProviderUrl(final URL providerUrl) {
+ private URL getRegistedProviderUrl(final URL providerUrl, final URL registryUrl) {
//The address you see at the registry
- final URL registedProviderUrl = providerUrl.removeParameters(getFilteredKeys(providerUrl))
- .removeParameter(Constants.MONITOR_KEY)
- .removeParameter(Constants.BIND_IP_KEY)
- .removeParameter(Constants.BIND_PORT_KEY)
- .removeParameter(QOS_ENABLE)
- .removeParameter(QOS_PORT)
- .removeParameter(ACCEPT_FOREIGN_IP)
- .removeParameter(VALIDATION_KEY)
- .removeParameter(INTERFACES);
- return registedProviderUrl;
+ if(!registryUrl.getParameter(Constants.SIMPLE_KEY,false)){
+ final URL registedProviderUrl = providerUrl.removeParameters(getFilteredKeys(providerUrl))
+ .removeParameter(Constants.MONITOR_KEY)
+ .removeParameter(Constants.BIND_IP_KEY)
+ .removeParameter(Constants.BIND_PORT_KEY)
+ .removeParameter(QOS_ENABLE)
+ .removeParameter(QOS_PORT)
+ .removeParameter(ACCEPT_FOREIGN_IP)
+ .removeParameter(VALIDATION_KEY)
+ .removeParameter(INTERFACES);
+ return registedProviderUrl;
+ }else{
+ String[] addionalParameterKeys = registryUrl.getParameter(ADD_PARAM_KEYS_KEY, new String[0]);
+ String[] registryParams = {APPLICATION_KEY, CODEC_KEY, EXCHANGER_KEY, SERIALIZATION_KEY, CLUSTER_KEY, CONNECTIONS_KEY, DEPRECATED_KEY,
+ GROUP_KEY, LOADBALANCE_KEY, MOCK_KEY, PATH_KEY, TIMEOUT_KEY, TOKEN_KEY, VERSION_KEY, WARMUP_KEY, WEIGHT_KEY, TIMESTAMP_KEY};
+ ArrayUtils.addAll(registryParams, addionalParameterKeys);
+ String[] methods = providerUrl.getParameter(METHODS_KEY, (String[]) null);
+ return URL.valueOf(providerUrl, registryParams, methods);
+ }
+
}
private URL getSubscribedOverrideUrl(URL registedProviderUrl) {
@@ -363,8 +392,7 @@ public class RegistryProtocol implements Protocol {
URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, parameters.remove(Constants.REGISTER_IP_KEY), 0, type.getName(), parameters);
if (!Constants.ANY_VALUE.equals(url.getServiceInterface())
&& url.getParameter(Constants.REGISTER_KEY, true)) {
- registry.register(subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY,
- Constants.CHECK_KEY, String.valueOf(false)));
+ registry.register(getRegistedConsumerUrl(subscribeUrl, directory.getUrl()));
}
directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY,
Constants.PROVIDERS_CATEGORY
@@ -376,6 +404,21 @@ public class RegistryProtocol implements Protocol {
return invoker;
}
+ private URL getRegistedConsumerUrl(final URL consumerUrl, URL registryUrl) {
+ if(!registryUrl.getParameter(Constants.SIMPLE_KEY,false)){
+ return consumerUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY,
+ Constants.CHECK_KEY, String.valueOf(false));
+ }else{
+ String[] addionalParameterKeys = registryUrl.getParameter(ADD_PARAM_KEYS_KEY, new String[0]);
+ String[] registryParams = {APPLICATION_KEY, CODEC_KEY, EXCHANGER_KEY, SERIALIZATION_KEY, CLUSTER_KEY, CONNECTIONS_KEY, DEPRECATED_KEY,
+ GROUP_KEY, LOADBALANCE_KEY, MOCK_KEY, PATH_KEY, TIMEOUT_KEY, TOKEN_KEY, VERSION_KEY, WARMUP_KEY, WEIGHT_KEY, TIMESTAMP_KEY};
+ ArrayUtils.addAll(registryParams, addionalParameterKeys);
+ String[] methods = consumerUrl.getParameter(METHODS_KEY, (String[]) null);
+ return URL.valueOf(consumerUrl, registryParams, methods).addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY,
+ Constants.CHECK_KEY, String.valueOf(false));
+ }
+ }
+
@Override
public void destroy() {
List<Exporter<?>> exporters = new ArrayList<Exporter<?>>(bounds.values());
diff --git a/dubbo-servicedata/dubbo-servicedata-api/pom.xml b/dubbo-servicedata/dubbo-servicedata-api/pom.xml
new file mode 100644
index 0000000..af5d30b
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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-servicedata</artifactId>
+ <groupId>org.apache.dubbo</groupId>
+ <version>2.7.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dubbo-servicedata-api</artifactId>
+ <packaging>jar</packaging>
+
+ <properties>
+ <skip_maven_deploy>false</skip_maven_deploy>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-cluster</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-common</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-container-api</artifactId>
+ <version>${project.parent.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/ServiceStore.java
similarity index 50%
copy from dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java
copy to dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/ServiceStore.java
index 4d35c78..cfad3fc 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/ServiceStore.java
@@ -1,52 +1,40 @@
-/*
- * 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;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.Adaptive;
-import org.apache.dubbo.common.extension.SPI;
-import org.apache.dubbo.config.dynamic.DynamicConfiguration;
-
-/**
- * RouterFactory. (SPI, Singleton, ThreadSafe)
- * <p>
- * <a href="http://en.wikipedia.org/wiki/Routing">Routing</a>
- *
- * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
- * @see org.apache.dubbo.rpc.cluster.Directory#list(org.apache.dubbo.rpc.Invocation)
- */
-@SPI
-public interface RouterFactory {
-
- /**
- * Create router.
- *
- * @param url
- * @return router
- */
- @Adaptive("protocol")
- Router getRouter(URL url);
-
- /**
- * @param dynamicConfiguration
- * @param url reserved for future usage.
- * @return
- */
- default Router getRouter(DynamicConfiguration dynamicConfiguration, URL url) {
- return null;
- }
-}
\ No newline at end of file
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.servicedata;
+
+
+import org.apache.dubbo.common.URL;
+
+/**
+ */
+public interface ServiceStore {
+
+ /**
+ *
+ * @param url e.g: dubbo://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=kylin or
+ * consumer://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=kylin
+ */
+ void put(URL url);
+
+ /**
+ *
+ * @param url eg: dubbo://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=cvictory&category=provider or
+ * eg: consumer://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=cvictory&category=consumer
+ * @return
+ */
+ URL peek(URL url);
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/ServiceStoreFactory.java
similarity index 53%
copy from dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java
copy to dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/ServiceStoreFactory.java
index 4d35c78..f5d351f 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/ServiceStoreFactory.java
@@ -1,52 +1,30 @@
-/*
- * 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;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.Adaptive;
-import org.apache.dubbo.common.extension.SPI;
-import org.apache.dubbo.config.dynamic.DynamicConfiguration;
-
-/**
- * RouterFactory. (SPI, Singleton, ThreadSafe)
- * <p>
- * <a href="http://en.wikipedia.org/wiki/Routing">Routing</a>
- *
- * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
- * @see org.apache.dubbo.rpc.cluster.Directory#list(org.apache.dubbo.rpc.Invocation)
- */
-@SPI
-public interface RouterFactory {
-
- /**
- * Create router.
- *
- * @param url
- * @return router
- */
- @Adaptive("protocol")
- Router getRouter(URL url);
-
- /**
- * @param dynamicConfiguration
- * @param url reserved for future usage.
- * @return
- */
- default Router getRouter(DynamicConfiguration dynamicConfiguration, URL url) {
- return null;
- }
-}
\ No newline at end of file
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.servicedata;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Adaptive;
+import org.apache.dubbo.common.extension.SPI;
+
+/**
+ */
+@SPI("dubbo")
+public interface ServiceStoreFactory {
+
+ @Adaptive({"protocol"})
+ ServiceStore getServiceStore(URL url);
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/integration/ServiceStoreService.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/integration/ServiceStoreService.java
new file mode 100644
index 0000000..8fad3a8
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/integration/ServiceStoreService.java
@@ -0,0 +1,81 @@
+/*
+ * 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.servicedata.integration;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.servicedata.ServiceStore;
+import org.apache.dubbo.servicedata.ServiceStoreFactory;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+/**
+ */
+public class ServiceStoreService {
+
+ private ServiceStoreFactory serviceStoreFactory = ExtensionLoader.getExtensionLoader(ServiceStoreFactory.class).getAdaptiveExtension();
+ private static final Set<URL> providerURLs = new HashSet<URL>();
+ private static final Set<URL> consumerURLs = new HashSet<URL>();
+ private ServiceStore serviceStore;
+
+ private URL serviceStoreUrl;
+
+ private ServiceStoreService(URL serviceStoreURL) {
+ if (Constants.SERVICE_STORE_KEY.equals(serviceStoreURL.getProtocol())) {
+ String protocol = serviceStoreURL.getParameter(Constants.SERVICE_STORE_KEY, Constants.DEFAULT_DIRECTORY);
+ serviceStoreURL = serviceStoreURL.setProtocol(protocol).removeParameter(Constants.SERVICE_STORE_KEY);
+ }
+ this.serviceStoreUrl = serviceStoreURL;
+ serviceStore = serviceStoreFactory.getServiceStore(this.serviceStoreUrl);
+ }
+
+ private static ServiceStoreService serviceStoreService;
+ private static Object lock = new Object();
+
+ public static ServiceStoreService instance(Supplier<URL> loadServiceStoreUrl) {
+ if (serviceStoreService == null) {
+ synchronized (lock) {
+ if (serviceStoreService == null) {
+ URL serviceStoreURL = loadServiceStoreUrl.get();
+ if (serviceStoreURL == null) {
+ return null;
+ }
+ serviceStoreService = new ServiceStoreService(serviceStoreURL);
+ }
+ }
+ }
+ return serviceStoreService;
+ }
+
+ public void publishProvider(URL providerUrl) throws RpcException {
+ providerURLs.add(providerUrl);
+ serviceStore.put(providerUrl);
+ }
+
+ public void publishConsumer(URL consumerURL) throws RpcException {
+ consumerURLs.add(consumerURL);
+ serviceStore.put(consumerURL);
+ }
+
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/support/AbstractServiceStore.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/support/AbstractServiceStore.java
new file mode 100644
index 0000000..5002b52
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/support/AbstractServiceStore.java
@@ -0,0 +1,279 @@
+/*
+ * 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.servicedata.support;
+
+import org.apache.dubbo.common.Constants;
+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.ConcurrentHashSet;
+import org.apache.dubbo.common.utils.ConfigUtils;
+import org.apache.dubbo.common.utils.NamedThreadFactory;
+import org.apache.dubbo.servicedata.ServiceStore;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ */
+public abstract class AbstractServiceStore implements ServiceStore {
+
+
+ // URL address separator, used in file cache, service provider URL separation
+ private static final char URL_SEPARATOR = ' ';
+ // URL address separated regular expression for parsing the service provider URL list in the file cache
+ private static final String URL_SPLIT = "\\s+";
+ // Log output
+ protected final Logger logger = LoggerFactory.getLogger(getClass());
+ // Local disk cache, where the special key value.registies records the list of registry centers, and the others are the list of notified service providers
+ final Properties properties = new Properties();
+ // File cache timing writing
+ private final ExecutorService servicestoreCacheExecutor = Executors.newFixedThreadPool(1, new NamedThreadFactory("DubboSaveServicestoreCache", true));
+
+ private final AtomicLong lastCacheChanged = new AtomicLong();
+ private final Set<URL> registered = new ConcurrentHashSet<URL>();
+ final Set<URL> failedServiceStore = new ConcurrentHashSet<URL>();
+ private URL serviceStoreURL;
+ // Local disk cache file
+ File file;
+ private AtomicBoolean INIT = new AtomicBoolean(false);
+ private final ScheduledExecutorService retryExecutor = Executors.newScheduledThreadPool(0, new NamedThreadFactory("DubboRegistryFailedRetryTimer", true));
+ private AtomicInteger retryTimes = new AtomicInteger(0);
+
+ public AbstractServiceStore(URL servicestoreURL) {
+ setUrl(servicestoreURL);
+ // Start file save timer
+ String filename = servicestoreURL.getParameter(Constants.FILE_KEY, System.getProperty("user.home") + "/.dubbo/dubbo-servicestore-" + servicestoreURL.getParameter(Constants.APPLICATION_KEY) + "-" + servicestoreURL.getAddress() + ".cache");
+ File file = null;
+ if (ConfigUtils.isNotEmpty(filename)) {
+ file = new File(filename);
+ if (!file.exists() && file.getParentFile() != null && !file.getParentFile().exists()) {
+ if (!file.getParentFile().mkdirs()) {
+ throw new IllegalArgumentException("Invalid service store file " + file + ", cause: Failed to create directory " + file.getParentFile() + "!");
+ }
+ }
+ // if this file exist, firstly delete it.
+ if (!INIT.getAndSet(true) && file.exists()) {
+ file.delete();
+ }
+ }
+ this.file = file;
+ loadProperties();
+ retryExecutor.scheduleWithFixedDelay(new Runnable() {
+ @Override
+ public void run() {
+ // Check and connect to the registry
+ try {
+ retry();
+ } catch (Throwable t) { // Defensive fault tolerance
+ logger.error("Unexpected error occur at failed retry, cause: " + t.getMessage(), t);
+ }
+ }
+ }, 100, 100, TimeUnit.MILLISECONDS);
+ }
+
+ public URL getUrl() {
+ return serviceStoreURL;
+ }
+
+ protected void setUrl(URL url) {
+ if (url == null) {
+ throw new IllegalArgumentException("servicestore url == null");
+ }
+ this.serviceStoreURL = url;
+ }
+
+ public Set<URL> getRegistered() {
+ return registered;
+ }
+
+ private void doSaveProperties(long version) {
+ if (version < lastCacheChanged.get()) {
+ return;
+ }
+ if (file == null) {
+ return;
+ }
+ // Save
+ try {
+ File lockfile = new File(file.getAbsolutePath() + ".lock");
+ if (!lockfile.exists()) {
+ lockfile.createNewFile();
+ }
+ RandomAccessFile raf = new RandomAccessFile(lockfile, "rw");
+ try {
+ FileChannel channel = raf.getChannel();
+ try {
+ FileLock lock = channel.tryLock();
+ if (lock == null) {
+ throw new IOException("Can not lock the servicestore cache file " + file.getAbsolutePath() + ", ignore and retry later, maybe multi java process use the file, please config: dubbo.servicestore.file=xxx.properties");
+ }
+ // Save
+ try {
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+ FileOutputStream outputFile = new FileOutputStream(file);
+ try {
+ properties.store(outputFile, "Dubbo Servicestore Cache");
+ } finally {
+ outputFile.close();
+ }
+ } finally {
+ lock.release();
+ }
+ } finally {
+ channel.close();
+ }
+ } finally {
+ raf.close();
+ }
+ } catch (Throwable e) {
+ if (version < lastCacheChanged.get()) {
+ return;
+ } else {
+ servicestoreCacheExecutor.execute(new SaveProperties(lastCacheChanged.incrementAndGet()));
+ }
+ logger.warn("Failed to save service store file, cause: " + e.getMessage(), e);
+ }
+ }
+
+ void loadProperties() {
+ if (file != null && file.exists()) {
+ InputStream in = null;
+ try {
+ in = new FileInputStream(file);
+ properties.load(in);
+ if (logger.isInfoEnabled()) {
+ logger.info("Load service store file " + file + ", data: " + properties);
+ }
+ } catch (Throwable e) {
+ logger.warn("Failed to load service store file " + file, e);
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ logger.warn(e.getMessage(), e);
+ }
+ }
+ }
+ }
+ }
+
+ private void saveProperties(URL url, boolean add) {
+ if (file == null) {
+ return;
+ }
+
+ try {
+ if (add) {
+ properties.setProperty(url.getServiceKey(), url.toFullString());
+ } else {
+ properties.remove(url.getServiceKey());
+ }
+ long version = lastCacheChanged.incrementAndGet();
+ servicestoreCacheExecutor.execute(new SaveProperties(version));
+ } catch (Throwable t) {
+ logger.warn(t.getMessage(), t);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getUrl().toString();
+ }
+
+ private class SaveProperties implements Runnable {
+ private long version;
+
+ private SaveProperties(long version) {
+ this.version = version;
+ }
+
+ @Override
+ public void run() {
+ doSaveProperties(version);
+ }
+ }
+
+ public void put(URL url) {
+ try {
+ // remove the individul param
+ url = url.removeParameters(Constants.PID_KEY, Constants.TIMESTAMP_KEY);
+ if (logger.isInfoEnabled()) {
+ logger.info("Servicestore Put: " + url);
+ }
+ failedServiceStore.remove(url);
+ doPutService(url);
+ saveProperties(url, true);
+ } catch (Exception e) {
+ // retry again. If failed again, throw exception.
+ failedServiceStore.add(url);
+ logger.error("Failed to put servicestore " + url + " in " + getUrl().toFullString() + ", cause: " + e.getMessage(), e);
+ }
+ }
+
+
+ public URL peek(URL url) {
+ try {
+ if (logger.isInfoEnabled()) {
+ logger.info("Servicestore Peek: " + url);
+ }
+ return doPeekService(url);
+ } catch (Exception e) {
+ logger.error("Failed to peek servicestore " + url + " in " + getUrl().toFullString() + ", cause: " + e.getMessage(), e);
+ }
+ return null;
+ }
+
+ public void retry() {
+ if (retryTimes.incrementAndGet() > 120000 && failedServiceStore.isEmpty()) {
+ retryExecutor.shutdown();
+ }
+ if (failedServiceStore.isEmpty()) {
+ return;
+ }
+ for (URL url : new HashSet<URL>(failedServiceStore)) {
+ this.put(url);
+ }
+ }
+
+
+ protected abstract void doPutService(URL url);
+
+ protected abstract URL doPeekService(URL url);
+
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreFactory.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreFactory.java
new file mode 100644
index 0000000..96fe7e9
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreFactory.java
@@ -0,0 +1,80 @@
+/*
+ * 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.servicedata.support;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.servicedata.ServiceStore;
+import org.apache.dubbo.servicedata.ServiceStoreFactory;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ */
+public abstract class AbstractServiceStoreFactory implements ServiceStoreFactory {
+
+ // Log output
+ private static final Logger LOGGER = LoggerFactory.getLogger(AbstractServiceStoreFactory.class);
+
+ // The lock for the acquisition process of the registry
+ private static final ReentrantLock LOCK = new ReentrantLock();
+
+ // Registry Collection Map<RegistryAddress, Registry>
+ private static final Map<String, ServiceStore> SERVICE_STORE_MAP = new ConcurrentHashMap<String, ServiceStore>();
+
+ /**
+ * Get all registries
+ *
+ * @return all registries
+ */
+ public static Collection<ServiceStore> getServiceStores() {
+ return Collections.unmodifiableCollection(SERVICE_STORE_MAP.values());
+ }
+
+ @Override
+ public ServiceStore getServiceStore(URL url) {
+ url = url.setPath(ServiceStore.class.getName())
+ .addParameter(Constants.INTERFACE_KEY, ServiceStore.class.getName())
+ .removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY);
+ String key = url.toServiceString();
+ // Lock the registry access process to ensure a single instance of the registry
+ LOCK.lock();
+ try {
+ ServiceStore serviceStore = SERVICE_STORE_MAP.get(key);
+ if (serviceStore != null) {
+ return serviceStore;
+ }
+ serviceStore = createServiceStore(url);
+ if (serviceStore == null) {
+ throw new IllegalStateException("Can not create servicestore " + url);
+ }
+ SERVICE_STORE_MAP.put(key, serviceStore);
+ return serviceStore;
+ } finally {
+ // Release the lock
+ LOCK.unlock();
+ }
+ }
+
+ protected abstract ServiceStore createServiceStore(URL url);
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/integration/ServiceStoreServiceTest.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/integration/ServiceStoreServiceTest.java
new file mode 100644
index 0000000..75aa87c
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/integration/ServiceStoreServiceTest.java
@@ -0,0 +1,7 @@
+package org.apache.dubbo.servicedata.integration;
+
+/**
+ * @author cvictory ON 2018/9/14
+ */
+public class ServiceStoreServiceTest {
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreFactoryTest.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreFactoryTest.java
new file mode 100644
index 0000000..94cf1bf
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreFactoryTest.java
@@ -0,0 +1,72 @@
+package org.apache.dubbo.servicedata.support;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.servicedata.ServiceStore;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author cvictory ON 2018/9/14
+ */
+public class AbstractServiceStoreFactoryTest {
+
+ private AbstractServiceStoreFactory serviceStoreFactory = new AbstractServiceStoreFactory() {
+ @Override
+ protected ServiceStore createServiceStore(URL url) {
+ return new ServiceStore() {
+
+ Map<String, String> store = new ConcurrentHashMap<>();
+
+ @Override
+ public void put(URL url) {
+ store.put(url.getServiceKey(), url.toParameterString());
+ }
+
+ @Override
+ public URL peek(URL url) {
+ String queryV = store.get(url.getServiceKey());
+ return url.clearParameters().addParameterString(queryV);
+ }
+ };
+ }
+ };
+
+ @Test
+ public void testGetOneServiceStore() {
+ URL url = URL.valueOf("zookeeper://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic");
+ ServiceStore serviceStore1 = serviceStoreFactory.getServiceStore(url);
+ ServiceStore serviceStore2 = serviceStoreFactory.getServiceStore(url);
+ Assert.assertEquals(serviceStore1, serviceStore2);
+ }
+
+ @Test
+ public void testGetOneServiceStoreForIpFormat() {
+ URL url1 = URL.valueOf("zookeeper://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic");
+ URL url2 = URL.valueOf("zookeeper://" + NetUtils.getLocalAddress().getHostAddress() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic");
+ ServiceStore serviceStore1 = serviceStoreFactory.getServiceStore(url1);
+ ServiceStore serviceStore2 = serviceStoreFactory.getServiceStore(url2);
+ Assert.assertEquals(serviceStore1, serviceStore2);
+ }
+
+ @Test
+ public void testGetForDiffService() {
+ URL url1 = URL.valueOf("zookeeper://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService1?version=1.0.0&application=vic");
+ URL url2 = URL.valueOf("zookeeper://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService2?version=1.0.0&application=vic");
+ ServiceStore serviceStore1 = serviceStoreFactory.getServiceStore(url1);
+ ServiceStore serviceStore2 = serviceStoreFactory.getServiceStore(url2);
+ Assert.assertEquals(serviceStore1, serviceStore2);
+ }
+
+ @Test
+ public void testGetForDiffGroup() {
+ URL url1 = URL.valueOf("zookeeper://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic&group=aaa");
+ URL url2 = URL.valueOf("zookeeper://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic&group=bbb");
+ ServiceStore serviceStore1 = serviceStoreFactory.getServiceStore(url1);
+ ServiceStore serviceStore2 = serviceStoreFactory.getServiceStore(url2);
+ Assert.assertNotEquals(serviceStore1, serviceStore2);
+ }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreTest.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreTest.java
new file mode 100644
index 0000000..2134296
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.servicedata.support;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ *
+ */
+public class AbstractServiceStoreTest {
+
+ private NewServiceStore abstractServiceStore;
+ private NewServiceStore singleServiceStore;
+
+ @Before
+ public void before() {
+ URL url = URL.valueOf("zookeeper://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic");
+ abstractServiceStore = new NewServiceStore(url);
+ URL singleUrl = URL.valueOf("redis://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=singleTest");
+ singleServiceStore = new NewServiceStore(singleUrl);
+ }
+
+ @Test
+ public void testPutUsual() {
+ URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic");
+ abstractServiceStore.put(url);
+ Assert.assertNotNull(abstractServiceStore.store.get(url.getServiceKey()));
+ }
+
+ @Test
+ public void testPutNoServiceKeyUrl() {
+ URL urlTmp = URL.valueOf("rmi://wrongHost:90?application=vic");
+ abstractServiceStore.put(urlTmp);
+ Assert.assertNull(urlTmp.getServiceKey());
+ // key is null, will add failed list.
+ Assert.assertFalse(abstractServiceStore.failedServiceStore.isEmpty());
+ }
+
+ @Test
+ public void testPutNotFullServiceKeyUrl() {
+ URL urlTmp = URL.valueOf("rmi://wrongHost:90/org.dubbo.TestService");
+ abstractServiceStore.put(urlTmp);
+ Assert.assertNotNull(abstractServiceStore.store.get(urlTmp.getServiceKey()));
+ }
+
+ @Test
+ public void testFileExistAfterPut() throws InterruptedException {
+ Assert.assertFalse(singleServiceStore.file.exists());
+ URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic");
+ singleServiceStore.put(url);
+ Thread.sleep(2000);
+ Assert.assertTrue(singleServiceStore.file.exists());
+ Assert.assertTrue(singleServiceStore.properties.containsKey(url.getServiceKey()));
+ }
+
+ @Test
+ public void testPeek() {
+ URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic");
+ abstractServiceStore.put(url);
+ URL result = abstractServiceStore.peek(url);
+ Assert.assertEquals(url, result);
+ }
+
+
+ private static class NewServiceStore extends AbstractServiceStore {
+
+ Map<String, String> store = new ConcurrentHashMap<>();
+
+ public NewServiceStore(URL servicestoreURL) {
+ super(servicestoreURL);
+ }
+
+ @Override
+ protected void doPutService(URL url) {
+ store.put(url.getServiceKey(), url.toParameterString());
+ }
+
+ @Override
+ protected URL doPeekService(URL url) {
+ String queryV = store.get(url.getServiceKey());
+ URL urlTmp = url.clearParameters().addParameterString(queryV);
+ return urlTmp;
+ }
+ }
+
+
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-redis/pom.xml b/dubbo-servicedata/dubbo-servicedata-redis/pom.xml
new file mode 100644
index 0000000..2896c33
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-redis/pom.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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-servicedata</artifactId>
+ <groupId>org.apache.dubbo</groupId>
+ <version>2.7.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dubbo-servicedata-redis</artifactId>
+ <properties>
+ <jedis.version>2.9.0</jedis.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-servicedata-api</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>redis.clients</groupId>
+ <artifactId>jedis</artifactId>
+ <version>${jedis.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.curator</groupId>
+ <artifactId>curator-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStore.java b/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStore.java
new file mode 100644
index 0000000..52a2861
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStore.java
@@ -0,0 +1,73 @@
+/*
+ * 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.servicedata.redis;
+
+import org.apache.dubbo.common.Constants;
+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.RpcException;
+import org.apache.dubbo.servicedata.support.AbstractServiceStore;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPool;
+import redis.clients.jedis.JedisPoolConfig;
+
+/**
+ * ZookeeperRegistry
+ */
+public class RedisServiceStore extends AbstractServiceStore {
+
+ private final static Logger logger = LoggerFactory.getLogger(RedisServiceStore.class);
+
+ private final static String TAG = "sd.";
+
+ private final JedisPool pool;
+
+ public RedisServiceStore(URL url) {
+ super(url);
+ pool = new JedisPool(new JedisPoolConfig(), url.getHost(), url.getPort());
+ }
+
+ @Override
+ protected void doPutService(URL url) {
+ try (Jedis jedis = pool.getResource()) {
+ jedis.set(TAG + getProtocol(url) + "." + url.getServiceKey(), url.toParameterString());
+ } catch (Throwable e) {
+ logger.error("Failed to put " + url + " to redis " + url + ", cause: " + e.getMessage(), e);
+ throw new RpcException("Failed to put " + url + " to redis " + getUrl() + ", cause: " + e.getMessage(), e);
+ }
+ }
+
+ @Override
+ protected URL doPeekService(URL url) {
+ try (Jedis jedis = pool.getResource()) {
+ String value = jedis.get(TAG + getProtocol(url) + "." + url.getServiceKey());
+ return url.addParameterString(value);
+ } catch (Throwable e) {
+ logger.error("Failed to peek " + url + " to redis " + url + ", cause: " + e.getMessage(), e);
+ throw new RpcException("Failed to put " + url + " to redis " + getUrl() + ", cause: " + e.getMessage(), e);
+ }
+ }
+
+ private String getProtocol(URL url) {
+ String protocol = url.getParameter(Constants.SIDE_KEY);
+ protocol = protocol == null ? url.getProtocol() : protocol;
+ return protocol;
+ }
+
+
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStoreFactory.java b/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStoreFactory.java
new file mode 100644
index 0000000..eccf433
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStoreFactory.java
@@ -0,0 +1,36 @@
+/*
+ * 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.servicedata.redis;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
+import org.apache.dubbo.servicedata.ServiceStore;
+import org.apache.dubbo.servicedata.support.AbstractServiceStoreFactory;
+
+/**
+ * ZookeeperRegistryFactory.
+ *
+ */
+public class RedisServiceStoreFactory extends AbstractServiceStoreFactory {
+
+
+ @Override
+ public ServiceStore createServiceStore(URL url) {
+ return new RedisServiceStore(url);
+ }
+
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-redis/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.ServiceStoreFactory b/dubbo-servicedata/dubbo-servicedata-redis/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.ServiceStoreFactory
new file mode 100644
index 0000000..b5caef2
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-redis/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.ServiceStoreFactory
@@ -0,0 +1 @@
+redis=org.apache.dubbo.servicedata.redis.RedisServiceStoreFactory
diff --git a/dubbo-servicedata/dubbo-servicedata-zookeeper/pom.xml b/dubbo-servicedata/dubbo-servicedata-zookeeper/pom.xml
new file mode 100644
index 0000000..a9f9805
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-zookeeper/pom.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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-servicedata</artifactId>
+ <groupId>org.apache.dubbo</groupId>
+ <version>2.7.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dubbo-servicedata-zookeeper</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-servicedata-api</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-remoting-zookeeper</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.curator</groupId>
+ <artifactId>curator-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStore.java b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStore.java
new file mode 100644
index 0000000..486c8c0
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStore.java
@@ -0,0 +1,132 @@
+/*
+ * 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.servicedata.zookeeper;
+
+import org.apache.dubbo.common.Constants;
+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.UrlUtils;
+import org.apache.dubbo.remoting.zookeeper.ZookeeperClient;
+import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.servicedata.support.AbstractServiceStore;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * ZookeeperRegistry
+ */
+public class ZookeeperServiceStore extends AbstractServiceStore {
+
+ private final static Logger logger = LoggerFactory.getLogger(ZookeeperServiceStore.class);
+
+ private final static String DEFAULT_ROOT = "dubbo";
+
+ private final static String TAG = "servicestore";
+
+ private final String root;
+
+ private final ZookeeperClient zkClient;
+
+ public ZookeeperServiceStore(URL url, ZookeeperTransporter zookeeperTransporter) {
+ super(url);
+ if (url.isAnyHost()) {
+ throw new IllegalStateException("registry address == null");
+ }
+ String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT);
+ if (!group.startsWith(Constants.PATH_SEPARATOR)) {
+ group = Constants.PATH_SEPARATOR + group;
+ }
+ this.root = group;
+ zkClient = zookeeperTransporter.connect(url);
+ }
+
+ @Override
+ protected void doPutService(URL url) {
+ try {
+ deletePath(url);
+ url = url.removeParameters(Constants.BIND_IP_KEY, Constants.BIND_PORT_KEY, Constants.TIMESTAMP_KEY);
+ zkClient.create(toUrlPathWithParameter(url), false);
+ } catch (Throwable e) {
+ logger.error("Failed to put " + url + " to zookeeper " + url + ", cause: " + e.getMessage(), e);
+ throw new RpcException("Failed to put " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
+ }
+ }
+
+ private void deletePath(URL url) {
+ String path = toCategoryPath(url);
+ List<String> urlStrs = zkClient.getChildren(path);
+ if (CollectionUtils.isEmpty(urlStrs)) {
+ return;
+ }
+ for (String urlStr : urlStrs) {
+ zkClient.delete(path + Constants.PATH_SEPARATOR + urlStr);
+ }
+ }
+
+ @Override
+ protected URL doPeekService(final URL url) {
+ try {
+ List<String> urlStrs = zkClient.getChildren((toCategoryPath(url)));
+ List<URL> urls = new ArrayList<URL>();
+ if (urlStrs != null && !urlStrs.isEmpty()) {
+ for (String urlStr : urlStrs) {
+ urlStr = URL.decode(urlStr);
+ if (urlStr.contains("://")) {
+ urls.add(URL.valueOf(urlStr));
+ }
+ }
+ }
+ return urls.isEmpty() ? null : urls.get(0);
+ } catch (Throwable e) {
+ logger.error("Failed to peek " + url + " to zookeeper " + url + ", cause: " + e.getMessage(), e);
+ throw new RpcException("Failed to peek " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
+ }
+ }
+
+ private String toRootDir() {
+ if (root.equals(Constants.PATH_SEPARATOR)) {
+ return root;
+ }
+ return root + Constants.PATH_SEPARATOR;
+ }
+
+ private String toRootPath() {
+ return root;
+ }
+
+ private String toServicePath(URL url) {
+ String name = url.getServiceInterface();
+ if (Constants.ANY_VALUE.equals(name)) {
+ return toRootPath();
+ }
+ return toRootDir() + URL.encode(name);
+ }
+
+ private String toCategoryPath(URL url) {
+ String protocol = url.getParameter(Constants.SIDE_KEY);
+ return toServicePath(url) + Constants.PATH_SEPARATOR + TAG + Constants.PATH_SEPARATOR + (protocol != null ? protocol : url.getProtocol());
+ }
+
+ private String toUrlPathWithParameter(URL url) {
+ return toCategoryPath(url) + Constants.PATH_SEPARATOR + URL.encode(url.toParameterString());
+ }
+
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStoreFactory.java b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStoreFactory.java
new file mode 100644
index 0000000..4f0deb8
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStoreFactory.java
@@ -0,0 +1,41 @@
+/*
+ * 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.servicedata.zookeeper;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
+import org.apache.dubbo.servicedata.ServiceStore;
+import org.apache.dubbo.servicedata.support.AbstractServiceStoreFactory;
+
+/**
+ * ZookeeperRegistryFactory.
+ *
+ */
+public class ZookeeperServiceStoreFactory extends AbstractServiceStoreFactory {
+
+ private ZookeeperTransporter zookeeperTransporter;
+
+ public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter) {
+ this.zookeeperTransporter = zookeeperTransporter;
+ }
+
+ @Override
+ public ServiceStore createServiceStore(URL url) {
+ return new ZookeeperServiceStore(url, zookeeperTransporter);
+ }
+
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.ServiceStoreFactory b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.ServiceStoreFactory
new file mode 100644
index 0000000..ed32c44
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.ServiceStoreFactory
@@ -0,0 +1 @@
+zookeeper=org.apache.dubbo.servicedata.zookeeper.ZookeeperServiceStoreFactory
diff --git a/dubbo-servicedata/pom.xml b/dubbo-servicedata/pom.xml
new file mode 100644
index 0000000..25964ff
--- /dev/null
+++ b/dubbo-servicedata/pom.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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-parent</artifactId>
+ <groupId>org.apache.dubbo</groupId>
+ <version>2.7.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dubbo-servicedata</artifactId>
+ <packaging>pom</packaging>
+ <modules>
+ <module>dubbo-servicedata-api</module>
+ <module>dubbo-servicedata-zookeeper</module>
+ <module>dubbo-servicedata-redis</module>
+ </modules>
+
+
+</project>
diff --git a/pom.xml b/pom.xml
index 5bd895d..d326e85 100644
--- a/pom.xml
+++ b/pom.xml
@@ -145,6 +145,7 @@
<module>dubbo-bom</module>
<module>dubbo-all</module>
<module>dubbo-distribution</module>
+ <module>dubbo-servicedata</module>
</modules>
<dependencyManagement>