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 e8da094  Refactor the dynamic-config module to governance module
e8da094 is described below

commit e8da094255618a1665a9cd6397881a89bbc2a8a5
Author: ken.lj <[email protected]>
AuthorDate: Wed Oct 17 17:42:28 2018 +0800

    Refactor the dynamic-config module to governance module
---
 dubbo-governance/dubbo-governance-api/pom.xml      |  40 ++++
 .../governance/AbstractDynamicConfiguration.java   |  80 +++++++
 .../apache/dubbo/governance/ConfigChangeEvent.java |  70 ++++++
 .../apache/dubbo/governance/ConfigChangeType.java  |  26 +++
 .../org/apache/dubbo/governance/ConfigType.java    |  25 +++
 .../dubbo/governance/ConfigurationListener.java    |  29 +++
 .../dubbo/governance/DynamicConfiguration.java     |  42 ++++
 .../governance/DynamicConfigurationFactory.java    |  33 +++
 .../support/nop/NopDynamicConfiguration.java       |  46 ++++
 .../nop/NopDynamicConfigurationFactory.java        |  31 +++
 ...ubbo.config.dynamic.DynamicConfigurationFactory |   1 +
 dubbo-governance/dubbo-governance-apollo/pom.xml   |  44 ++++
 .../support/apollo/ApolloDynamicConfiguration.java | 140 ++++++++++++
 .../apollo/ApolloDynamicConfigurationFactory.java  |  39 ++++
 ...pache.dubbo.config.dynamic.DynamicConfiguration |   1 +
 ...ubbo.config.dynamic.DynamicConfigurationFactory |   1 +
 .../dubbo-governance-zookeeper/pom.xml             |  54 +++++
 .../archaius/ArchaiusDynamicConfiguration.java     | 124 +++++++++++
 .../ArchaiusDynamicConfigurationFactory.java       |  39 ++++
 .../sources/ZooKeeperConfigurationSource.java      | 244 +++++++++++++++++++++
 ...pache.dubbo.config.dynamic.DynamicConfiguration |   2 +
 ...ubbo.config.dynamic.DynamicConfigurationFactory |   2 +
 dubbo-governance/pom.xml                           |  38 ++++
 23 files changed, 1151 insertions(+)

diff --git a/dubbo-governance/dubbo-governance-api/pom.xml 
b/dubbo-governance/dubbo-governance-api/pom.xml
new file mode 100644
index 0000000..4a847b1
--- /dev/null
+++ b/dubbo-governance/dubbo-governance-api/pom.xml
@@ -0,0 +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.
+  -->
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns="http://maven.apache.org/POM/4.0.0";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.dubbo</groupId>
+        <artifactId>dubbo-governance</artifactId>
+        <version>2.7.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>dubbo-governance-api</artifactId>
+    <packaging>jar</packaging>
+    <name>${project.artifactId}</name>
+    <description>The api definition of the service governance 
module</description>
+    <properties>
+        <skip_maven_deploy>false</skip_maven_deploy>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-common</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git 
a/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/AbstractDynamicConfiguration.java
 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/AbstractDynamicConfiguration.java
new file mode 100644
index 0000000..6769883
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/AbstractDynamicConfiguration.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.governance;
+
+import org.apache.dubbo.common.URL;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ *
+ */
+public abstract class AbstractDynamicConfiguration<TargetConfigListener> 
implements DynamicConfiguration {
+    protected URL url;
+    /**
+     * One key can register multiple target listeners, but one target listener 
only maps to one configuration listener
+     */
+    private ConcurrentMap<String, ConcurrentMap<ConfigurationListener, 
TargetConfigListener>> listenerToTargetListenerMap = new ConcurrentHashMap<>();
+
+    public AbstractDynamicConfiguration() {
+    }
+
+    @Override
+    public void addListener(String key, ConfigurationListener listener) {
+        ConcurrentMap<ConfigurationListener, TargetConfigListener> listeners = 
listenerToTargetListenerMap.computeIfAbsent(key, k -> new 
ConcurrentHashMap<>());
+        TargetConfigListener targetListener = 
listeners.computeIfAbsent(listener, k -> createTargetConfigListener(key, 
listener));
+        addTargetListener(key, targetListener);
+    }
+
+    @Override
+    public String getConfig(String key, String group) {
+        return getConfig(key, group, null);
+    }
+
+    @Override
+    public String getConfig(String key, String group, ConfigurationListener 
listener) {
+        return getConfig(key, group, 0l, listener);
+    }
+
+    @Override
+    public String getConfig(String key, String group, long timeout, 
ConfigurationListener listener) {
+        try {
+            if (listener != null) {
+                this.addListener(key, listener);
+            }
+            return getInternalProperty(key, group, timeout);
+        } catch (Exception e) {
+            throw new IllegalStateException(e.getMessage(), e);
+        }
+    }
+
+    public URL getUrl() {
+        return url;
+    }
+
+    public void setUrl(URL url) {
+        this.url = url;
+    }
+
+    protected abstract String getInternalProperty(String key, String group, 
long timeout);
+
+    protected abstract void addTargetListener(String key, TargetConfigListener 
listener);
+
+    protected abstract TargetConfigListener createTargetConfigListener(String 
key, ConfigurationListener listener);
+
+}
diff --git 
a/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/ConfigChangeEvent.java
 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/ConfigChangeEvent.java
new file mode 100644
index 0000000..bc8504b
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/ConfigChangeEvent.java
@@ -0,0 +1,70 @@
+/*
+ * 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.governance;
+
+/**
+ *
+ */
+public class ConfigChangeEvent {
+    private String key;
+    private String newValue;
+    private ConfigChangeType changeType;
+    private ConfigType type;
+
+    public ConfigChangeEvent(String key, String value, ConfigType type) {
+        this(key, value, type, ConfigChangeType.MODIFIED);
+    }
+
+    public ConfigChangeEvent(String key, String value, ConfigType type, 
ConfigChangeType changeType) {
+        this.key = key;
+        this.newValue = value;
+        this.type = type;
+        this.changeType = changeType;
+    }
+
+    public String getKey() {
+        return key;
+    }
+
+    public void setKey(String key) {
+        this.key = key;
+    }
+
+    public String getNewValue() {
+        return newValue;
+    }
+
+    public void setNewValue(String newValue) {
+        this.newValue = newValue;
+    }
+
+    public ConfigChangeType getChangeType() {
+        return changeType;
+    }
+
+    public void setChangeType(ConfigChangeType changeType) {
+        this.changeType = changeType;
+    }
+
+    public ConfigType getType() {
+        return type;
+    }
+
+    public void setType(ConfigType type) {
+        this.type = type;
+    }
+}
diff --git 
a/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/ConfigChangeType.java
 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/ConfigChangeType.java
new file mode 100644
index 0000000..81b59e8
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/ConfigChangeType.java
@@ -0,0 +1,26 @@
+/*
+ * 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.governance;
+
+/**
+ *
+ */
+public enum ConfigChangeType {
+    ADDED,
+    MODIFIED,
+    DELETED
+}
diff --git 
a/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/ConfigType.java
 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/ConfigType.java
new file mode 100644
index 0000000..f084372
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/ConfigType.java
@@ -0,0 +1,25 @@
+/*
+ * 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.governance;
+
+/**
+ *
+ */
+public enum ConfigType {
+    CONFIGURATORS,
+    ROUTERS
+}
diff --git 
a/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/ConfigurationListener.java
 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/ConfigurationListener.java
new file mode 100644
index 0000000..128d4a1
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/ConfigurationListener.java
@@ -0,0 +1,29 @@
+/*
+ * 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.governance;
+
+import org.apache.dubbo.common.URL;
+
+/**
+ *
+ */
+public interface ConfigurationListener {
+
+    void process(ConfigChangeEvent event);
+
+    URL getUrl();
+}
diff --git 
a/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/DynamicConfiguration.java
 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/DynamicConfiguration.java
new file mode 100644
index 0000000..f07affe
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/DynamicConfiguration.java
@@ -0,0 +1,42 @@
+/*
+ * 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.governance;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.SPI;
+
+/**
+ *
+ */
+@SPI("zookeeper")
+public interface DynamicConfiguration {
+
+    void init();
+
+    URL getUrl();
+
+    void setUrl(URL url);
+
+    void addListener(String key, ConfigurationListener listener);
+
+    String getConfig(String key, String group);
+
+    String getConfig(String key, String group, long timeout, 
ConfigurationListener listener);
+
+    String getConfig(String key, String group, ConfigurationListener listener);
+
+}
diff --git 
a/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/DynamicConfigurationFactory.java
 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/DynamicConfigurationFactory.java
new file mode 100644
index 0000000..d4e8930
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/DynamicConfigurationFactory.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.governance;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Adaptive;
+import org.apache.dubbo.common.extension.SPI;
+
+/**
+ *
+ */
+@SPI("nop")
+public interface DynamicConfigurationFactory {
+
+    @Adaptive({Constants.CONFIG_TYPE_KEY})
+    DynamicConfiguration getDynamicConfiguration(URL url);
+
+}
diff --git 
a/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/support/nop/NopDynamicConfiguration.java
 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/support/nop/NopDynamicConfiguration.java
new file mode 100644
index 0000000..e773a33
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/support/nop/NopDynamicConfiguration.java
@@ -0,0 +1,46 @@
+/*
+ * 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.governance.support.nop;
+
+import org.apache.dubbo.governance.AbstractDynamicConfiguration;
+import org.apache.dubbo.governance.ConfigurationListener;
+
+/**
+ *
+ */
+public class NopDynamicConfiguration extends AbstractDynamicConfiguration {
+
+    @Override
+    public void init() {
+
+    }
+
+    @Override
+    protected String getInternalProperty(String key, String group, long 
timeout) {
+        return null;
+    }
+
+    @Override
+    protected void addTargetListener(String key, Object o) {
+
+    }
+
+    @Override
+    protected Object createTargetConfigListener(String key, 
ConfigurationListener listener) {
+        return null;
+    }
+}
diff --git 
a/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/support/nop/NopDynamicConfigurationFactory.java
 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/support/nop/NopDynamicConfigurationFactory.java
new file mode 100644
index 0000000..62f2232
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-api/src/main/java/org/apache/dubbo/governance/support/nop/NopDynamicConfigurationFactory.java
@@ -0,0 +1,31 @@
+/*
+ * 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.governance.support.nop;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.governance.DynamicConfiguration;
+import org.apache.dubbo.governance.DynamicConfigurationFactory;
+
+/**
+ *
+ */
+public class NopDynamicConfigurationFactory implements 
DynamicConfigurationFactory {
+    @Override
+    public DynamicConfiguration getDynamicConfiguration(URL url) {
+        return new NopDynamicConfiguration();
+    }
+}
diff --git 
a/dubbo-governance/dubbo-governance-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfigurationFactory
 
b/dubbo-governance/dubbo-governance-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfigurationFactory
new file mode 100644
index 0000000..9a769be
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfigurationFactory
@@ -0,0 +1 @@
+nop=org.apache.dubbo.governance.support.nop.NopDynamicConfigurationFactory
\ No newline at end of file
diff --git a/dubbo-governance/dubbo-governance-apollo/pom.xml 
b/dubbo-governance/dubbo-governance-apollo/pom.xml
new file mode 100644
index 0000000..52a5d39
--- /dev/null
+++ b/dubbo-governance/dubbo-governance-apollo/pom.xml
@@ -0,0 +1,44 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns="http://maven.apache.org/POM/4.0.0";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.dubbo</groupId>
+        <artifactId>dubbo-governance</artifactId>
+        <version>2.7.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>dubbo-governance-apollo</artifactId>
+    <packaging>jar</packaging>
+    <name>${project.artifactId}</name>
+    <description>The Apollo implementation of the governance api</description>
+    <properties>
+        <skip_maven_deploy>false</skip_maven_deploy>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-governance-api</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.ctrip.framework.apollo</groupId>
+            <artifactId>apollo-client</artifactId>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git 
a/dubbo-governance/dubbo-governance-apollo/src/main/java/org/apache/dubbo/governance/support/apollo/ApolloDynamicConfiguration.java
 
b/dubbo-governance/dubbo-governance-apollo/src/main/java/org/apache/dubbo/governance/support/apollo/ApolloDynamicConfiguration.java
new file mode 100644
index 0000000..70d8c5e
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-apollo/src/main/java/org/apache/dubbo/governance/support/apollo/ApolloDynamicConfiguration.java
@@ -0,0 +1,140 @@
+/*
+ * 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.governance.support.apollo;
+
+import com.ctrip.framework.apollo.Config;
+import com.ctrip.framework.apollo.ConfigChangeListener;
+import com.ctrip.framework.apollo.ConfigService;
+import com.ctrip.framework.apollo.enums.ConfigSourceType;
+import com.ctrip.framework.apollo.enums.PropertyChangeType;
+import com.ctrip.framework.apollo.model.ConfigChange;
+import com.ctrip.framework.apollo.model.ConfigChangeEvent;
+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.StringUtils;
+import org.apache.dubbo.governance.AbstractDynamicConfiguration;
+import org.apache.dubbo.governance.ConfigChangeType;
+import org.apache.dubbo.governance.ConfigType;
+import org.apache.dubbo.governance.ConfigurationListener;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ *
+ */
+public class ApolloDynamicConfiguration extends 
AbstractDynamicConfiguration<ConfigChangeListener> {
+    private static final Logger logger = 
LoggerFactory.getLogger(ApolloDynamicConfiguration.class);
+    private static final String APOLLO_ENV_KEY = "env";
+    private static final String APOLLO_ADDR_KEY = "apollo.meta";
+    private static final String APOLLO_CLUSTER_KEY = "apollo.cluster";
+    private static final String APPLO_DEFAULT_NAMESPACE = "dubbo";
+
+    private Config dubboConfig;
+
+    public ApolloDynamicConfiguration() {
+
+    }
+
+    @Override
+    public void init() {
+        /**
+         * Instead of using Dubbo's configuration, I would suggest use the 
original configuration method Apollo provides.
+         */
+//        String configEnv = env.getCompositeConf().getString(ENV_KEY);
+//        String configCluster = env.getCompositeConf().getString(CLUSTER_KEY);
+        String configEnv = url.getParameter(Constants.CONFIG_ENV_KEY);
+        String configAddr = url.getAddress();
+        String configCluster = url.getParameter(Constants.CONFIG_CLUSTER_KEY);
+        if (configEnv != null) {
+            System.setProperty(APOLLO_ENV_KEY, configEnv);
+        }
+        if (StringUtils.isEmpty(configEnv) && 
!Constants.ANYHOST_VALUE.equals(configAddr)) {
+            System.setProperty(APOLLO_ADDR_KEY, configAddr);
+        }
+        if (configCluster != null) {
+            System.setProperty(APOLLO_CLUSTER_KEY, configCluster);
+        }
+
+        dubboConfig = 
ConfigService.getConfig(url.getParameter(Constants.CONFIG_NAMESPACE_KEY, 
APPLO_DEFAULT_NAMESPACE));
+        // Decide to fail or to continue when failed to connect to remote 
server.
+        boolean check = url.getParameter(Constants.CONFIG_CHECK_KEY, false);
+        if (dubboConfig.getSourceType() != ConfigSourceType.REMOTE) {
+            if (check) {
+                throw new IllegalStateException("Failed to connect to 
ConfigCenter, the ConfigCenter is Apollo, the address is: " + 
(StringUtils.isNotEmpty(configAddr) ? configAddr : configEnv));
+            } else {
+                logger.warn("Failed to connect to ConfigCenter, the 
ConfigCenter is Apollo, " +
+                        "the address is: " + 
(StringUtils.isNotEmpty(configAddr) ? configAddr : configEnv) +
+                        ". will use the local cache value instead before 
finally connected.");
+            }
+        }
+    }
+
+    @Override
+    protected String getInternalProperty(String key, String group, long 
timeout) {
+        return dubboConfig.getProperty(key, null);
+    }
+
+    @Override
+    protected void addTargetListener(String key, ConfigChangeListener 
listener) {
+        Set<String> keys = new HashSet<>(1);
+        keys.add(key);
+        this.dubboConfig.addChangeListener(listener, keys);
+    }
+
+    @Override
+    protected ConfigChangeListener createTargetConfigListener(String key, 
ConfigurationListener listener) {
+        return new ApolloListener(listener);
+    }
+
+    public ConfigChangeType getChangeType(ConfigChange change) {
+        if (change.getChangeType() == PropertyChangeType.DELETED || 
StringUtils.isEmpty(change.getNewValue())) {
+            return ConfigChangeType.DELETED;
+        }
+        return ConfigChangeType.MODIFIED;
+    }
+
+    private class ApolloListener implements ConfigChangeListener {
+        private ConfigurationListener listener;
+        private URL url;
+
+        public ApolloListener(ConfigurationListener listener) {
+            this(listener.getUrl(), listener);
+        }
+
+        public ApolloListener(URL url, ConfigurationListener listener) {
+            this.url = url;
+            this.listener = listener;
+        }
+
+        @Override
+        public void onChange(ConfigChangeEvent changeEvent) {
+            for (String key : changeEvent.changedKeys()) {
+                ConfigChange change = changeEvent.getChange(key);
+                // TODO Maybe we no longer need to identify the type of 
change. Because there's no scenario that a callback will subscribe for both 
configurators and routers
+                if 
(change.getPropertyName().endsWith(Constants.CONFIGURATORS_SUFFIX)) {
+                    listener.process(new 
org.apache.dubbo.governance.ConfigChangeEvent(key, change.getNewValue(), 
ConfigType.CONFIGURATORS, getChangeType(change)));
+                } else {
+                    listener.process(new 
org.apache.dubbo.governance.ConfigChangeEvent(key, change.getNewValue(), 
ConfigType.ROUTERS, getChangeType(change)));
+                }
+            }
+        }
+    }
+
+}
diff --git 
a/dubbo-governance/dubbo-governance-apollo/src/main/java/org/apache/dubbo/governance/support/apollo/ApolloDynamicConfigurationFactory.java
 
b/dubbo-governance/dubbo-governance-apollo/src/main/java/org/apache/dubbo/governance/support/apollo/ApolloDynamicConfigurationFactory.java
new file mode 100644
index 0000000..5117a6f
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-apollo/src/main/java/org/apache/dubbo/governance/support/apollo/ApolloDynamicConfigurationFactory.java
@@ -0,0 +1,39 @@
+/*
+ * 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.governance.support.apollo;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.governance.DynamicConfiguration;
+import org.apache.dubbo.governance.DynamicConfigurationFactory;
+
+/**
+ *
+ */
+public class ApolloDynamicConfigurationFactory implements 
DynamicConfigurationFactory {
+
+    private DynamicConfiguration configuration;
+
+    @Override
+    public synchronized DynamicConfiguration getDynamicConfiguration(URL url) {
+        if (configuration == null) {
+            configuration = new ApolloDynamicConfiguration();
+            configuration.setUrl(url);
+            configuration.init();
+        }
+        return configuration;
+    }
+}
diff --git 
a/dubbo-governance/dubbo-governance-apollo/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfiguration
 
b/dubbo-governance/dubbo-governance-apollo/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfiguration
new file mode 100644
index 0000000..5a5af4f
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-apollo/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfiguration
@@ -0,0 +1 @@
+apollo=org.apache.dubbo.governance.support.apollo.ApolloDynamicConfiguration
\ No newline at end of file
diff --git 
a/dubbo-governance/dubbo-governance-apollo/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfigurationFactory
 
b/dubbo-governance/dubbo-governance-apollo/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfigurationFactory
new file mode 100644
index 0000000..3a89f53
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-apollo/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfigurationFactory
@@ -0,0 +1 @@
+apollo=org.apache.dubbo.governance.support.apollo.ApolloDynamicConfigurationFactory
\ No newline at end of file
diff --git a/dubbo-governance/dubbo-governance-zookeeper/pom.xml 
b/dubbo-governance/dubbo-governance-zookeeper/pom.xml
new file mode 100644
index 0000000..1d061b3
--- /dev/null
+++ b/dubbo-governance/dubbo-governance-zookeeper/pom.xml
@@ -0,0 +1,54 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns="http://maven.apache.org/POM/4.0.0";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.dubbo</groupId>
+        <artifactId>dubbo-governance</artifactId>
+        <version>2.7.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>dubbo-governance-zookeeper</artifactId>
+    <packaging>jar</packaging>
+    <name>${project.artifactId}</name>
+    <description>The zookeeper implementation of the governance 
api</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-governance-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>com.netflix.archaius</groupId>
+            <artifactId>archaius-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-framework</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-recipes</artifactId>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git 
a/dubbo-governance/dubbo-governance-zookeeper/src/main/java/org/apache/dubbo/governance/support/archaius/ArchaiusDynamicConfiguration.java
 
b/dubbo-governance/dubbo-governance-zookeeper/src/main/java/org/apache/dubbo/governance/support/archaius/ArchaiusDynamicConfiguration.java
new file mode 100644
index 0000000..32b8f62
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-zookeeper/src/main/java/org/apache/dubbo/governance/support/archaius/ArchaiusDynamicConfiguration.java
@@ -0,0 +1,124 @@
+/*
+ * 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.governance.support.archaius;
+
+import com.netflix.config.ConfigurationManager;
+import com.netflix.config.DynamicPropertyFactory;
+import com.netflix.config.DynamicStringProperty;
+import com.netflix.config.DynamicWatchedConfiguration;
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.governance.AbstractDynamicConfiguration;
+import org.apache.dubbo.governance.ConfigChangeEvent;
+import org.apache.dubbo.governance.ConfigChangeType;
+import org.apache.dubbo.governance.ConfigType;
+import org.apache.dubbo.governance.ConfigurationListener;
+import 
org.apache.dubbo.governance.support.archaius.sources.ZooKeeperConfigurationSource;
+
+/**
+ * Archaius supports various sources and it's extensiable: JDBC, ZK, 
Properties, ..., so should we make it extensiable?
+ */
+public class ArchaiusDynamicConfiguration extends 
AbstractDynamicConfiguration<Runnable> {
+
+    public ArchaiusDynamicConfiguration() {
+    }
+
+    @Override
+    public void init() {
+        //  String address = env.getCompositeConf().getString(ADDRESS_KEY);
+        //  String app = env.getCompositeConf().getString(APP_KEY);
+
+        String address = url.getParameter(Constants.CONFIG_ADDRESS_KEY, 
url.getAddress());
+        if (!address.equals(Constants.ANYHOST_VALUE)) {
+            
System.setProperty(ZooKeeperConfigurationSource.ARCHAIUS_SOURCE_ADDRESS_KEY, 
address);
+        }
+        
System.setProperty(ZooKeeperConfigurationSource.ARCHAIUS_CONFIG_ROOT_PATH_KEY, 
url.getParameter(Constants.CONFIG_NAMESPACE_KEY, 
ZooKeeperConfigurationSource.DEFAULT_CONFIG_ROOT_PATH));
+        
System.setProperty(ZooKeeperConfigurationSource.ARCHAIUS_CONFIG_CHECK_KEY, 
url.getParameter(Constants.CONFIG_CHECK_KEY, "false"));
+
+        try {
+            ZooKeeperConfigurationSource zkConfigSource = new 
ZooKeeperConfigurationSource();
+            zkConfigSource.start();
+            /*if (!zkConfigSource.isConnected()) {
+                // we can check the status of config center here, and decide 
to fail or continue if we cannot reach the config server.
+            }*/
+            DynamicWatchedConfiguration zkDynamicConfig = new 
DynamicWatchedConfiguration(zkConfigSource);
+            ConfigurationManager.install(zkDynamicConfig);
+        } catch (Exception e) {
+            throw new IllegalStateException(e.getMessage(), e);
+        }
+    }
+
+    @Override
+    protected String getInternalProperty(String key, String group, long 
timeout) {
+        return DynamicPropertyFactory.getInstance()
+                .getStringProperty(key, null)
+                .get();
+    }
+
+    @Override
+    protected void addTargetListener(String key, Runnable runnable) {
+        DynamicStringProperty prop = DynamicPropertyFactory.getInstance()
+                .getStringProperty(key, null);
+        prop.addCallback(runnable);
+    }
+
+    @Override
+    protected Runnable createTargetConfigListener(String key, 
ConfigurationListener listener) {
+        return new ArchaiusListener(key, listener);
+    }
+
+
+    private class ArchaiusListener implements Runnable {
+        private ConfigurationListener listener;
+        private URL url;
+        private String key;
+        private ConfigType type;
+
+        public ArchaiusListener(String key, ConfigurationListener listener) {
+            this.key = key;
+            this.listener = listener;
+            this.url = listener.getUrl();
+            // Maybe we no longer need to identify the type of change. Because 
there's no scenario that a callback will subscribe for both configurators and 
routers
+            if (key.endsWith(Constants.CONFIGURATORS_SUFFIX)) {
+                type = ConfigType.CONFIGURATORS;
+            } else {
+                /**
+                 * used for all router rules:
+                 * {@link Constants.ROUTERS_SUFFIX}
+                 * {@link 
org.apache.dubbo.rpc.cluster.router.tag.TagRouter.TAGRULE_DATAID}
+                 */
+                type = ConfigType.ROUTERS;
+            }
+        }
+
+        @Override
+        public void run() {
+            DynamicStringProperty prop = DynamicPropertyFactory.getInstance()
+                    .getStringProperty(key, null);
+            String newValue = prop.get();
+            ConfigChangeEvent event = new ConfigChangeEvent(key, newValue, 
type);
+            if (StringUtils.isEmpty(newValue)) {
+                event.setChangeType(ConfigChangeType.DELETED);
+                listener.process(event);
+            } else {
+                event.setChangeType(ConfigChangeType.MODIFIED);
+                listener.process(event);
+            }
+        }
+    }
+}
diff --git 
a/dubbo-governance/dubbo-governance-zookeeper/src/main/java/org/apache/dubbo/governance/support/archaius/ArchaiusDynamicConfigurationFactory.java
 
b/dubbo-governance/dubbo-governance-zookeeper/src/main/java/org/apache/dubbo/governance/support/archaius/ArchaiusDynamicConfigurationFactory.java
new file mode 100644
index 0000000..6da335a
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-zookeeper/src/main/java/org/apache/dubbo/governance/support/archaius/ArchaiusDynamicConfigurationFactory.java
@@ -0,0 +1,39 @@
+/*
+ * 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.governance.support.archaius;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.governance.DynamicConfiguration;
+import org.apache.dubbo.governance.DynamicConfigurationFactory;
+
+/**
+ *
+ */
+public class ArchaiusDynamicConfigurationFactory implements 
DynamicConfigurationFactory {
+
+    private volatile DynamicConfiguration configuration;
+
+    @Override
+    public synchronized DynamicConfiguration getDynamicConfiguration(URL url) {
+        if (configuration == null) {
+            configuration = new ArchaiusDynamicConfiguration();
+            configuration.setUrl(url);
+            configuration.init();
+        }
+        return configuration;
+    }
+}
diff --git 
a/dubbo-governance/dubbo-governance-zookeeper/src/main/java/org/apache/dubbo/governance/support/archaius/sources/ZooKeeperConfigurationSource.java
 
b/dubbo-governance/dubbo-governance-zookeeper/src/main/java/org/apache/dubbo/governance/support/archaius/sources/ZooKeeperConfigurationSource.java
new file mode 100644
index 0000000..1559572
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-zookeeper/src/main/java/org/apache/dubbo/governance/support/archaius/sources/ZooKeeperConfigurationSource.java
@@ -0,0 +1,244 @@
+/*
+ * 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.governance.support.archaius.sources;
+
+import com.google.common.io.Closeables;
+import com.netflix.config.WatchedConfigurationSource;
+import com.netflix.config.WatchedUpdateListener;
+import com.netflix.config.WatchedUpdateResult;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.recipes.cache.ChildData;
+import org.apache.curator.framework.recipes.cache.TreeCache;
+import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
+import org.apache.curator.framework.recipes.cache.TreeCacheListener;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ *
+ */
+public class ZooKeeperConfigurationSource implements 
WatchedConfigurationSource, Closeable {
+    public static final String ARCHAIUS_SOURCE_ADDRESS_KEY = 
"archaius.zk.address";
+    public static final String ARCHAIUS_CONFIG_ROOT_PATH_KEY = 
"archaius.zk.rootpath";
+    public static final String ARCHAIUS_CONFIG_CHECK_KEY = "archaius.zk.check";
+    public static final String DEFAULT_CONFIG_ROOT_PATH = "/dubbo/config";
+
+    private static final Logger logger = 
LoggerFactory.getLogger(ZooKeeperConfigurationSource.class);
+    private Executor executor = Executors.newFixedThreadPool(1);
+    private final CuratorFramework client;
+
+    private final String configRootPath;
+    private final TreeCache treeCache;
+    private boolean connected = false;
+
+    private final Charset charset = Charset.forName("UTF-8");
+
+    private List<WatchedUpdateListener> listeners = new 
CopyOnWriteArrayList<WatchedUpdateListener>();
+
+    public ZooKeeperConfigurationSource() {
+        this(System.getProperty(ARCHAIUS_SOURCE_ADDRESS_KEY), 60 * 1000, 
10000, System.getProperty(ARCHAIUS_CONFIG_ROOT_PATH_KEY, 
DEFAULT_CONFIG_ROOT_PATH));
+    }
+
+    public ZooKeeperConfigurationSource(int sessionTimeout, int 
connectTimeout, String configRootPath) {
+        this(System.getProperty(ARCHAIUS_SOURCE_ADDRESS_KEY), sessionTimeout, 
connectTimeout, configRootPath);
+    }
+
+
+    public ZooKeeperConfigurationSource(String connectString, int 
sessionTimeout, int connectTimeout, String configRootPath) {
+        if (connectString == null) {
+            throw new IllegalArgumentException("connectString==null, must 
specify the address to connect for zookeeper archaius source.");
+        }
+
+        CuratorFramework client = 
CuratorFrameworkFactory.newClient(connectString, sessionTimeout, connectTimeout,
+                new ExponentialBackoffRetry(1000, 3));
+        client.start();
+        try {
+            connected = client.blockUntilConnected(connectTimeout, 
TimeUnit.MILLISECONDS);
+            if (!connected) {
+                boolean check = 
Boolean.parseBoolean(System.getProperty(ARCHAIUS_CONFIG_CHECK_KEY, "false"));
+                if (check) {
+                    throw new IllegalStateException("Failed to connect to 
ConfigCenter Zookeeper : " + connectString + " in " + connectTimeout + "ms.");
+                } else {
+                    logger.warn("Cannot connect to ConfigCenter at zookeeper " 
+ connectString + " in " + connectTimeout + "ms");
+                }
+            }
+        } catch (InterruptedException e) {
+            throw new IllegalStateException("The thread was interrupted 
unexpectedly when try connecting to zookeeper " + connectString + " as 
ConfigCenter, ", e);
+        }
+        this.client = client;
+        this.configRootPath = configRootPath;
+        this.treeCache = new TreeCache(client, configRootPath);
+    }
+
+    /**
+     * Creates the pathChildrenCache using the CuratorFramework client and ZK 
root path node for the config
+     *
+     * @param client
+     * @param configRootPath path to ZK root parent node for the rest of the 
configuration properties (ie. /<my-app>/config)
+     */
+    public ZooKeeperConfigurationSource(CuratorFramework client, String 
configRootPath) {
+        this.client = client;
+        this.configRootPath = configRootPath;
+        this.treeCache = new TreeCache(client, configRootPath);
+    }
+
+    /**
+     * Adds a listener to the pathChildrenCache, initializes the cache, then 
starts the cache-management background thread
+     *
+     * @throws Exception
+     */
+    public void start() throws Exception {
+        // create the watcher for future configuration updatess
+        treeCache.getListenable().addListener(new TreeCacheListener() {
+            public void childEvent(CuratorFramework aClient, TreeCacheEvent 
event)
+                    throws Exception {
+
+                TreeCacheEvent.Type type = event.getType();
+                ChildData data = event.getData();
+                if (type == TreeCacheEvent.Type.INITIALIZED || type == 
TreeCacheEvent.Type.CONNECTION_RECONNECTED) {
+                    connected = true;
+                }
+
+                // TODO, ignore other event types
+                if (data == null) {
+                    return;
+                }
+
+                if (data.getPath().split("/").length == 5) {
+                    byte[] value = data.getData();
+                    String stringValue = new String(value, charset);
+
+                    // fire event to all listeners
+                    Map<String, Object> added = null;
+                    Map<String, Object> changed = null;
+                    Map<String, Object> deleted = null;
+
+                    switch (type) {
+                        case NODE_ADDED:
+                            added = new HashMap<>(1);
+                            added.put(pathToKey(data.getPath()), stringValue);
+                            break;
+                        case NODE_REMOVED:
+                            deleted = new HashMap<>(1);
+                            deleted.put(pathToKey(data.getPath()), 
stringValue);
+                            break;
+                        case NODE_UPDATED:
+                            changed = new HashMap<>(1);
+                            changed.put(pathToKey(data.getPath()), 
stringValue);
+                    }
+
+                    WatchedUpdateResult result = 
WatchedUpdateResult.createIncremental(added,
+                            changed, deleted);
+
+                    fireEvent(result);
+                }
+            }
+        }, executor);
+
+        // passing true to trigger an initial rebuild upon starting.  
(blocking call)
+        treeCache.start();
+    }
+
+    /**
+     * This is used to convert a configuration nodePath into a key
+     *
+     * @param path
+     * @return key (nodePath less the config root path)
+     */
+    private String pathToKey(String path) {
+        if (StringUtils.isEmpty(path)) {
+            return path;
+        }
+        return path.replace(configRootPath + "/", "").replaceAll("/", ".");
+    }
+
+    @Override
+    public Map<String, Object> getCurrentData() throws Exception {
+        logger.debug("getCurrentData() retrieving current data.");
+
+        Map<String, Object> all = new HashMap<>();
+
+        if (!connected) {
+            logger.warn("ConfigCenter is not connected yet, zookeeper don't 
support local snapshot yet, so there's no old data to use!");
+            return all;
+        }
+
+        Map<String, ChildData> dataMap = 
treeCache.getCurrentChildren(configRootPath);
+        if (dataMap != null && dataMap.size() > 0) {
+            dataMap.forEach((childPath, v) -> {
+                String fullChildPath = configRootPath + "/" + childPath;
+                
treeCache.getCurrentChildren(fullChildPath).forEach((subChildPath, childData) 
-> {
+                    all.put(pathToKey(fullChildPath + "/" + subChildPath), new 
String(childData.getData(), charset));
+                });
+            });
+        }
+
+        logger.debug("getCurrentData() retrieved [{}] config elements.", 
all.size());
+
+        return all;
+    }
+
+    @Override
+    public void addUpdateListener(WatchedUpdateListener l) {
+        if (l != null) {
+            listeners.add(l);
+        }
+    }
+
+    @Override
+    public void removeUpdateListener(WatchedUpdateListener l) {
+        if (l != null) {
+            listeners.remove(l);
+        }
+    }
+
+    protected void fireEvent(WatchedUpdateResult result) {
+        for (WatchedUpdateListener l : listeners) {
+            try {
+                l.updateConfiguration(result);
+            } catch (Throwable ex) {
+                logger.error("Error in invoking WatchedUpdateListener", ex);
+            }
+        }
+    }
+
+    public void close() {
+        try {
+            Closeables.close(treeCache, true);
+        } catch (IOException exc) {
+            logger.error("IOException should not have been thrown.", exc);
+        }
+    }
+
+    public boolean isConnected() {
+        return connected;
+    }
+}
diff --git 
a/dubbo-governance/dubbo-governance-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfiguration
 
b/dubbo-governance/dubbo-governance-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfiguration
new file mode 100644
index 0000000..2918cd7
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfiguration
@@ -0,0 +1,2 @@
+archaius=org.apache.dubbo.governance.support.archaius.ArchaiusDynamicConfiguration
+zookeeper=org.apache.dubbo.governance.support.archaius.ArchaiusDynamicConfiguration
\ No newline at end of file
diff --git 
a/dubbo-governance/dubbo-governance-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfigurationFactory
 
b/dubbo-governance/dubbo-governance-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfigurationFactory
new file mode 100644
index 0000000..d2acc22
--- /dev/null
+++ 
b/dubbo-governance/dubbo-governance-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.dynamic.DynamicConfigurationFactory
@@ -0,0 +1,2 @@
+zookeeper=org.apache.dubbo.governance.support.archaius.ArchaiusDynamicConfigurationFactory
+archaius=org.apache.dubbo.governance.support.archaius.ArchaiusDynamicConfigurationFactory
\ No newline at end of file
diff --git a/dubbo-governance/pom.xml b/dubbo-governance/pom.xml
new file mode 100644
index 0000000..67f22d5
--- /dev/null
+++ b/dubbo-governance/pom.xml
@@ -0,0 +1,38 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns="http://maven.apache.org/POM/4.0.0";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.dubbo</groupId>
+        <artifactId>dubbo-parent</artifactId>
+        <version>2.7.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>dubbo-governance</artifactId>
+    <packaging>pom</packaging>
+    <name>${project.artifactId}</name>
+    <description>The service governance module of the Dubbo 
project</description>
+    <properties>
+        <skip_maven_deploy>false</skip_maven_deploy>
+    </properties>
+
+    <modules>
+        <module>dubbo-governance-api</module>
+        <module>dubbo-governance-apollo</module>
+        <module>dubbo-governance-zookeeper</module>
+    </modules>
+</project>
\ No newline at end of file

Reply via email to