This is an automated email from the ASF dual-hosted git repository.

liujun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo.git


The following commit(s) were added to refs/heads/master by this push:
     new e8bcdb0  Merge pull request #3096, code review config center.
e8bcdb0 is described below

commit e8bcdb0661e6c8a40ae993dd617c26df43e48599
Author: Ian Luo <[email protected]>
AuthorDate: Wed Jan 2 10:10:49 2019 +0800

    Merge pull request #3096, code review config center.
    
    * polish javadoc
    
    * git rid of template class for apollo
    
    * get rid of template class for NopDynamicConfiguration
    
    * get rid of tempate class for ZookeeperDynamicConfiguration
    
    * get rid of AbstractDynamicConfiguration
    
    * get rid of AbstractConfiguration
    
    * fix compilation error
    
    * fix compilation error
    
    * polish code
---
 .../dubbo/common/config/AbstractConfiguration.java |  91 ---------------
 .../common/config/AbstractPrefixConfiguration.java |   7 +-
 .../common/config/CompositeConfiguration.java      |  10 +-
 .../apache/dubbo/common/config/Configuration.java  |  64 ++++++++++-
 .../common/config/EnvironmentConfiguration.java    |   2 +-
 .../dubbo/common/config/InmemoryConfiguration.java |   2 +-
 .../common/config/PropertiesConfiguration.java     |   2 +-
 .../dubbo/common/config/SystemConfiguration.java   |   2 +-
 .../configcenter/AbstractDynamicConfiguration.java | 127 ---------------------
 .../dubbo/configcenter/DynamicConfiguration.java   |  60 ++++++----
 .../support/nop/NopDynamicConfiguration.java       |  27 ++---
 .../mock/MockDynamicConfiguration.java             |  29 ++---
 .../support/apollo/ApolloDynamicConfiguration.java |  84 +++++++-------
 .../zookeeper/ZookeeperDynamicConfiguration.java   |  72 +++++-------
 14 files changed, 195 insertions(+), 384 deletions(-)

diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/AbstractConfiguration.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/AbstractConfiguration.java
deleted file mode 100644
index e660eb9..0000000
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/AbstractConfiguration.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.config;
-
-public abstract class AbstractConfiguration implements Configuration {
-
-    @Override
-    public String getString(String key) {
-        return convert(String.class, key, null);
-    }
-
-    @Override
-    public String getString(String key, String defaultValue) {
-        return convert(String.class, key, defaultValue);
-    }
-
-    @Override
-    public final Object getProperty(String key) {
-        return getProperty(key, null);
-    }
-
-    @Override
-    public Object getProperty(String key, Object defaultValue) {
-        Object value = getInternalProperty(key);
-        if (value == null) {
-            value = defaultValue;
-        }
-        return value;
-    }
-
-    @Override
-    public boolean containsKey(String key) {
-        return getProperty(key) != null;
-    }
-
-    protected abstract Object getInternalProperty(String key);
-
-    private <T> T convert(Class<T> cls, String key, T defaultValue) {
-        // we only process String properties for now
-        String value = (String) getProperty(key);
-
-        if (value == null) {
-            return defaultValue;
-        }
-
-        Object obj = value;
-        if (cls.isInstance(value)) {
-            return cls.cast(value);
-        }
-
-        if (String.class.equals(cls)) {
-            return cls.cast(value);
-        }
-
-        if (Boolean.class.equals(cls) || Boolean.TYPE.equals(cls)) {
-            obj = Boolean.valueOf(value);
-        } else if (Number.class.isAssignableFrom(cls) || cls.isPrimitive()) {
-            if (Integer.class.equals(cls) || Integer.TYPE.equals(cls)) {
-                obj = Integer.valueOf(value);
-            } else if (Long.class.equals(cls) || Long.TYPE.equals(cls)) {
-                obj = Long.valueOf(value);
-            } else if (Byte.class.equals(cls) || Byte.TYPE.equals(cls)) {
-                obj = Byte.valueOf(value);
-            } else if (Short.class.equals(cls) || Short.TYPE.equals(cls)) {
-                obj = Short.valueOf(value);
-            } else if (Float.class.equals(cls) || Float.TYPE.equals(cls)) {
-                obj = Float.valueOf(value);
-            } else if (Double.class.equals(cls) || Double.TYPE.equals(cls)) {
-                obj = Double.valueOf(value);
-            }
-        } else if (cls.isEnum()) {
-            obj = Enum.valueOf(cls.asSubclass(Enum.class), value);
-        }
-
-        return cls.cast(obj);
-    }
-}
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/AbstractPrefixConfiguration.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/AbstractPrefixConfiguration.java
index 8f53aa5..c7d1598 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/AbstractPrefixConfiguration.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/AbstractPrefixConfiguration.java
@@ -21,7 +21,7 @@ import org.apache.dubbo.common.utils.StringUtils;
 /**
  * This is an abstraction specially customized for the sequence Dubbo 
retrieves properties.
  */
-public abstract class AbstractPrefixConfiguration extends 
AbstractConfiguration {
+public abstract class AbstractPrefixConfiguration implements Configuration {
     protected String id;
     protected String prefix;
 
@@ -44,9 +44,10 @@ public abstract class AbstractPrefixConfiguration extends 
AbstractConfiguration
         if (value == null && StringUtils.isNotEmpty(prefix)) {
             value = getInternalProperty(prefix + key);
         }
+
         if (value == null) {
-            value = super.getProperty(key, defaultValue);
+            value = getInternalProperty(key);
         }
-        return value;
+        return value != null ? value : defaultValue;
     }
 }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/CompositeConfiguration.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/CompositeConfiguration.java
index a181aeb..b301ff0 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/CompositeConfiguration.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/CompositeConfiguration.java
@@ -16,6 +16,9 @@
  */
 package org.apache.dubbo.common.config;
 
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
@@ -23,7 +26,8 @@ import java.util.List;
 /**
  *
  */
-public class CompositeConfiguration extends AbstractConfiguration {
+public class CompositeConfiguration implements Configuration {
+    private Logger logger = 
LoggerFactory.getLogger(CompositeConfiguration.class);
 
     /**
      * List holding all the configuration
@@ -56,7 +60,7 @@ public class CompositeConfiguration extends 
AbstractConfiguration {
     }
 
     @Override
-    protected Object getInternalProperty(String key) {
+    public Object getInternalProperty(String key) {
         Configuration firstMatchingConfiguration = null;
         for (Configuration config : configList) {
             try {
@@ -65,7 +69,7 @@ public class CompositeConfiguration extends 
AbstractConfiguration {
                     break;
                 }
             } catch (Exception e) {
-                e.printStackTrace();
+                logger.error("Error when trying to get value for key " + key + 
" from " + config + ", will continue to try the next one.");
             }
         }
         if (firstMatchingConfiguration != null) {
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/Configuration.java 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/Configuration.java
index 8380b59..7937b9d 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/Configuration.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/Configuration.java
@@ -26,7 +26,9 @@ public interface Configuration {
      * @param key The configuration key.
      * @return The associated string.
      */
-    String getString(String key);
+    default String getString(String key) {
+        return convert(String.class, key, null);
+    }
 
     /**
      * Get a string associated with the given configuration key.
@@ -38,7 +40,9 @@ public interface Configuration {
      * @return The associated string if key is found and has valid
      * format, default value otherwise.
      */
-    String getString(String key, String defaultValue);
+    default String getString(String key, String defaultValue) {
+        return convert(String.class, key, defaultValue);
+    }
 
     /**
      * Gets a property from the configuration. This is the most basic get
@@ -56,7 +60,9 @@ public interface Configuration {
      * @return the value to which this configuration maps the specified key, or
      * null if the configuration contains no mapping for this key.
      */
-    Object getProperty(String key);
+    default Object getProperty(String key) {
+        return getProperty(key, null);
+    }
 
     /**
      * Gets a property from the configuration. The default value will return 
if the configuration doesn't contain
@@ -67,7 +73,12 @@ public interface Configuration {
      * @return the value to which this configuration maps the specified key, 
or default value if the configuration
      * contains no mapping for this key.
      */
-    Object getProperty(String key, Object defaultValue);
+    default Object getProperty(String key, Object defaultValue) {
+        Object value = getInternalProperty(key);
+        return value != null ? value : defaultValue;
+    }
+
+    Object getInternalProperty(String key);
 
     /**
      * Check if the configuration contains the specified key.
@@ -76,7 +87,50 @@ public interface Configuration {
      * @return {@code true} if the configuration contains a value for this
      * key, {@code false} otherwise
      */
-    boolean containsKey(String key);
+    default boolean containsKey(String key) {
+        return getProperty(key) != null;
+    }
+
+
+    default <T> T convert(Class<T> cls, String key, T defaultValue) {
+        // we only process String properties for now
+        String value = (String) getProperty(key);
+
+        if (value == null) {
+            return defaultValue;
+        }
+
+        Object obj = value;
+        if (cls.isInstance(value)) {
+            return cls.cast(value);
+        }
+
+        if (String.class.equals(cls)) {
+            return cls.cast(value);
+        }
+
+        if (Boolean.class.equals(cls) || Boolean.TYPE.equals(cls)) {
+            obj = Boolean.valueOf(value);
+        } else if (Number.class.isAssignableFrom(cls) || cls.isPrimitive()) {
+            if (Integer.class.equals(cls) || Integer.TYPE.equals(cls)) {
+                obj = Integer.valueOf(value);
+            } else if (Long.class.equals(cls) || Long.TYPE.equals(cls)) {
+                obj = Long.valueOf(value);
+            } else if (Byte.class.equals(cls) || Byte.TYPE.equals(cls)) {
+                obj = Byte.valueOf(value);
+            } else if (Short.class.equals(cls) || Short.TYPE.equals(cls)) {
+                obj = Short.valueOf(value);
+            } else if (Float.class.equals(cls) || Float.TYPE.equals(cls)) {
+                obj = Float.valueOf(value);
+            } else if (Double.class.equals(cls) || Double.TYPE.equals(cls)) {
+                obj = Double.valueOf(value);
+            }
+        } else if (cls.isEnum()) {
+            obj = Enum.valueOf(cls.asSubclass(Enum.class), value);
+        }
+
+        return cls.cast(obj);
+    }
 
 
 }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/EnvironmentConfiguration.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/EnvironmentConfiguration.java
index 0f6f00a..c6d6523 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/EnvironmentConfiguration.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/EnvironmentConfiguration.java
@@ -30,7 +30,7 @@ public class EnvironmentConfiguration extends 
AbstractPrefixConfiguration {
     }
 
     @Override
-    protected Object getInternalProperty(String key) {
+    public Object getInternalProperty(String key) {
         return System.getenv(key);
     }
 
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/InmemoryConfiguration.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/InmemoryConfiguration.java
index 76b6062..bfbed85 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/InmemoryConfiguration.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/InmemoryConfiguration.java
@@ -36,7 +36,7 @@ public class InmemoryConfiguration extends 
AbstractPrefixConfiguration {
     }
 
     @Override
-    protected Object getInternalProperty(String key) {
+    public Object getInternalProperty(String key) {
         return store.get(key);
     }
 
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/PropertiesConfiguration.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/PropertiesConfiguration.java
index d76c3a1..4f8b986 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/PropertiesConfiguration.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/PropertiesConfiguration.java
@@ -35,7 +35,7 @@ public class PropertiesConfiguration extends 
AbstractPrefixConfiguration {
     }
 
     @Override
-    protected Object getInternalProperty(String key) {
+    public Object getInternalProperty(String key) {
         return ConfigUtils.getProperty(key);
     }
 }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/SystemConfiguration.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/SystemConfiguration.java
index 2a5bb54..a594a87 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/SystemConfiguration.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/SystemConfiguration.java
@@ -33,7 +33,7 @@ public class SystemConfiguration extends 
AbstractPrefixConfiguration {
     }
 
     @Override
-    protected Object getInternalProperty(String key) {
+    public Object getInternalProperty(String key) {
         return System.getProperty(key);
     }
 
diff --git 
a/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/AbstractDynamicConfiguration.java
 
b/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/AbstractDynamicConfiguration.java
deleted file mode 100644
index 5b8d149..0000000
--- 
a/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/AbstractDynamicConfiguration.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.configcenter;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.config.AbstractConfiguration;
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-/**
- * Dynamic configuration template class. The concrete implementation needs to 
provide implementation for three methods.
- *
- * @see AbstractDynamicConfiguration#getTargetConfig(String, String, long)
- * @see AbstractDynamicConfiguration#addConfigurationListener(String key, 
String group, TargetListener, ConfigurationListener)
- * @see AbstractDynamicConfiguration#createTargetListener(String, String group)
- */
-public abstract class AbstractDynamicConfiguration<TargetListener> extends 
AbstractConfiguration
-        implements DynamicConfiguration {
-    protected static final String DEFAULT_GROUP = "dubbo";
-
-    protected URL url;
-
-    // One key can register multiple target listeners, but one target listener 
only maps to one configuration listener
-    protected ConcurrentMap<String, TargetListener> targetListeners = new 
ConcurrentHashMap<>();
-
-    public AbstractDynamicConfiguration() {
-    }
-
-    public AbstractDynamicConfiguration(URL url) {
-        this.url = url;
-        initWith(url);
-    }
-
-    @Override
-    public void addListener(String key, ConfigurationListener listener) {
-        addListener(key, DEFAULT_GROUP, listener);
-    }
-
-    @Override
-    public void addListener(String key, String group, ConfigurationListener 
listener) {
-        TargetListener targetListener = targetListeners.computeIfAbsent(group 
+ key, ignoreK -> this.createTargetListener(key, group));
-        addConfigurationListener(key, group, targetListener, listener);
-    }
-
-    @Override
-    public String getConfig(String key) {
-        return getConfig(key, null, 0L);
-    }
-
-    @Override
-    public String getConfig(String key, String group) {
-        return getConfig(key, group, 0L);
-    }
-
-
-    @Override
-    public String getConfig(String key, String group, long timeout) {
-        try {
-            return getTargetConfig(key, group, timeout);
-        } catch (Exception e) {
-            throw new IllegalStateException(e.getMessage(), e);
-        }
-    }
-
-    @Override
-    public void removeListener(String key, ConfigurationListener listener) {
-        removeListener(key, DEFAULT_GROUP, listener);
-    }
-
-    @Override
-    public void removeListener(String key, String group, ConfigurationListener 
listener) {
-        TargetListener targetListener = targetListeners.get(group + key);
-        if (targetListener != null) {
-            removeConfigurationListener(key, group, targetListener, listener);
-        }
-    }
-
-    protected abstract void initWith(URL url);
-
-    /**
-     * Fetch dynamic configuration from backend config storage. If timeout 
exceeds, exception should be thrown.
-     *
-     * @param key     property key
-     * @param group   group
-     * @param timeout timeout
-     * @return target config value
-     */
-    protected abstract String getTargetConfig(String key, String group, long 
timeout);
-
-    /**
-     * Register a native listener to the backend config storage so that Dubbo 
has chance to get notified when the
-     * value changes.
-     * @param key property key the native listener will listen on
-     * @param group to distinguish different set of properties
-     * @param targetListener Implementation dependent listener, such as, 
zookeeper watcher, Apollo listener, ...
-     * @param configurationListener Listener in Dubbo that will handle 
notification.
-     */
-    protected abstract void addConfigurationListener(String key, String group, 
TargetListener targetListener, ConfigurationListener configurationListener);
-
-    protected abstract void removeConfigurationListener(String key, String 
group, TargetListener targetListener, ConfigurationListener 
configurationListener);
-
-    /**
-     * Create a native listener for the backend config storage, eventually 
ConfigurationListener will get notified once
-     * the value changes.
-     *
-     * @param key      property key the native listener will listen on
-     * @param group    to distinguish different set of properties
-     * @return native listener for the backend config storage
-     */
-    protected abstract TargetListener createTargetListener(String key, String 
group);
-
-}
diff --git 
a/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/DynamicConfiguration.java
 
b/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/DynamicConfiguration.java
index 66ea5c3..620e8c2 100644
--- 
a/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/DynamicConfiguration.java
+++ 
b/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/DynamicConfiguration.java
@@ -18,88 +18,100 @@ package org.apache.dubbo.configcenter;
 
 import org.apache.dubbo.common.config.Configuration;
 import org.apache.dubbo.common.config.Environment;
-import org.apache.dubbo.common.extension.ExtensionLoader;
 
 import java.util.Optional;
 
+import static 
org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
+
 /**
  * Dynamic configuration
  */
 public interface DynamicConfiguration extends Configuration {
+    String DEFAULT_GROUP = "dubbo";
 
     /**
      * {@link #addListener(String, String, ConfigurationListener)}
+     *
      * @param key      the key to represent a configuration
      * @param listener configuration listener
      */
-    void addListener(String key, ConfigurationListener listener);
+    default void addListener(String key, ConfigurationListener listener) {
+        addListener(key, DEFAULT_GROUP, listener);
+    }
 
 
     /**
      * {@link #removeListener(String, String, ConfigurationListener)}
      *
-     * @param key
-     * @param listener
+     * @param key      the key to represent a configuration
+     * @param listener configuration listener
      */
-    void removeListener(String key, ConfigurationListener listener);
+    default void removeListener(String key, ConfigurationListener listener) {
+        removeListener(key, DEFAULT_GROUP, listener);
+    }
 
     /**
      * Register a configuration listener for a specified key
-     * The listener only works for service governance purpose, so the target 
group would always be the value user specifies at startup or 'dubbo' by default.
-     * This method will only register listener, which means it will not 
trigger a notification that contains the current value.
+     * The listener only works for service governance purpose, so the target 
group would always be the value user
+     * specifies at startup or 'dubbo' by default. This method will only 
register listener, which means it will not
+     * trigger a notification that contains the current value.
      *
-     * @param key
-     * @param group
-     * @param listener
+     * @param key      the key to represent a configuration
+     * @param group    the group where the key belongs to
+     * @param listener configuration listener
      */
     void addListener(String key, String group, ConfigurationListener listener);
 
     /**
      * Stops one listener from listening to value changes in the specified key.
      *
-     * @param key
-     * @param group
-     * @param listener
+     * @param key      the key to represent a configuration
+     * @param group    the group where the key belongs to
+     * @param listener configuration listener
      */
     void removeListener(String key, String group, ConfigurationListener 
listener);
 
     /**
      * Get the configuration mapped to the given key
      *
-     * @param key property key
+     * @param key the key to represent a configuration
      * @return target configuration mapped to the given key
      */
-    String getConfig(String key);
+    default String getConfig(String key) {
+        return getConfig(key, null, 0L);
+    }
 
     /**
      * Get the configuration mapped to the given key and the given group
      *
-     * @param key   property key
-     * @param group group
+     * @param key   the key to represent a configuration
+     * @param group the group where the key belongs to
      * @return target configuration mapped to the given key and the given group
      */
-    String getConfig(String key, String group);
+    default String getConfig(String key, String group) {
+        return getConfig(key, group, 0L);
+    }
 
     /**
      * Get the configuration mapped to the given key and the given group. If 
the
      * configuration fails to fetch after timeout exceeds, 
IllegalStateException will be thrown.
      *
-     * @param key      property key
-     * @param group    group
-     * @param timeout  timeout value for fetching the target config
+     * @param key     the key to represent a configuration
+     * @param group   the group where the key belongs to
+     * @param timeout timeout value for fetching the target config
      * @return target configuration mapped to the given key and the given 
group, IllegalStateException will be thrown
      * if timeout exceeds.
      */
     String getConfig(String key, String group, long timeout) throws 
IllegalStateException;
 
     /**
-     * I think this method is strongly related to DynamicConfiguration, so we 
should put it directly in the definition of this interface instead of a 
separated utility class.
+     * Find DynamicConfiguration instance
      *
-     * @return
+     * @return DynamicConfiguration instance
      */
     static DynamicConfiguration getDynamicConfiguration() {
         Optional<Configuration> optional = 
Environment.getInstance().getDynamicConfiguration();
-        return (DynamicConfiguration) optional.orElseGet(() -> 
ExtensionLoader.getExtensionLoader(DynamicConfigurationFactory.class)
+        return (DynamicConfiguration) optional.orElseGet(() -> 
getExtensionLoader(DynamicConfigurationFactory.class)
                 .getDefaultExtension()
                 .getDynamicConfiguration(null));
     }
diff --git 
a/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/support/nop/NopDynamicConfiguration.java
 
b/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/support/nop/NopDynamicConfiguration.java
index ebe9d0d..baa6f16 100644
--- 
a/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/support/nop/NopDynamicConfiguration.java
+++ 
b/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/support/nop/NopDynamicConfiguration.java
@@ -17,7 +17,6 @@
 package org.apache.dubbo.configcenter.support.nop;
 
 import org.apache.dubbo.common.URL;
-import org.apache.dubbo.configcenter.AbstractDynamicConfiguration;
 import org.apache.dubbo.configcenter.ConfigurationListener;
 import org.apache.dubbo.configcenter.DynamicConfiguration;
 
@@ -25,42 +24,30 @@ import org.apache.dubbo.configcenter.DynamicConfiguration;
  * The default extension of {@link DynamicConfiguration}. If user does not 
specify a config centre, or specifies one
  * that is not a valid extension, it will default to this one.
  */
-public class NopDynamicConfiguration extends AbstractDynamicConfiguration {
-
-    NopDynamicConfiguration() {
-    }
+public class NopDynamicConfiguration implements DynamicConfiguration {
 
     public NopDynamicConfiguration(URL url) {
-        super(url);
+        // no-op
     }
 
-    @Override
-    protected void initWith(URL url) {
-
-    }
 
     @Override
-    protected String getTargetConfig(String key, String group, long timeout) {
+    public Object getInternalProperty(String key) {
         return null;
     }
 
     @Override
-    protected void addConfigurationListener(String key, String group, Object 
targetListener, ConfigurationListener configurationListener) {
+    public void addListener(String key, String group, ConfigurationListener 
listener) {
         // no-op
     }
 
     @Override
-    protected void removeConfigurationListener(String key, String group, 
Object o, ConfigurationListener configurationListener) {
-
-    }
-
-    @Override
-    protected Object createTargetListener(String key, String group) {
-        return null;
+    public void removeListener(String key, String group, ConfigurationListener 
listener) {
+        // no-op
     }
 
     @Override
-    protected Object getInternalProperty(String key) {
+    public String getConfig(String key, String group, long timeout) throws 
IllegalStateException {
         return null;
     }
 }
diff --git 
a/dubbo-configcenter/dubbo-configcenter-api/src/test/java/org/apache/dubbo/configcenter/mock/MockDynamicConfiguration.java
 
b/dubbo-configcenter/dubbo-configcenter-api/src/test/java/org/apache/dubbo/configcenter/mock/MockDynamicConfiguration.java
index 387f49d..ecc939f 100644
--- 
a/dubbo-configcenter/dubbo-configcenter-api/src/test/java/org/apache/dubbo/configcenter/mock/MockDynamicConfiguration.java
+++ 
b/dubbo-configcenter/dubbo-configcenter-api/src/test/java/org/apache/dubbo/configcenter/mock/MockDynamicConfiguration.java
@@ -17,48 +17,33 @@
 package org.apache.dubbo.configcenter.mock;
 
 import org.apache.dubbo.common.URL;
-import org.apache.dubbo.configcenter.AbstractDynamicConfiguration;
 import org.apache.dubbo.configcenter.ConfigurationListener;
+import org.apache.dubbo.configcenter.DynamicConfiguration;
 
 /**
  *
  */
-public class MockDynamicConfiguration extends AbstractDynamicConfiguration {
-
-    MockDynamicConfiguration() {
-    }
-
-    MockDynamicConfiguration(URL url) {
-        super(url);
+public class MockDynamicConfiguration implements DynamicConfiguration {
+    public MockDynamicConfiguration(URL url) {
     }
 
     @Override
-    protected void initWith(URL url) {
-
-    }
-
-    @Override
-    protected String getTargetConfig(String key, String group, long timeout) {
+    public Object getInternalProperty(String key) {
         return null;
     }
 
     @Override
-    protected void addConfigurationListener(String key, String group, Object 
o, ConfigurationListener configurationListener) {
+    public void addListener(String key, String group, ConfigurationListener 
listener) {
 
     }
 
     @Override
-    protected void removeConfigurationListener(String key, String group, 
Object o, ConfigurationListener configurationListener) {
-
-    }
+    public void removeListener(String key, String group, ConfigurationListener 
listener) {
 
-    @Override
-    protected Object createTargetListener(String key, String group) {
-        return null;
     }
 
     @Override
-    protected Object getInternalProperty(String key) {
+    public String getConfig(String key, String group, long timeout) throws 
IllegalStateException {
         return null;
     }
 }
diff --git 
a/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java
 
b/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java
index 62cbab1..c73dcd7 100644
--- 
a/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java
+++ 
b/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java
@@ -21,10 +21,10 @@ 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.configcenter.AbstractDynamicConfiguration;
 import org.apache.dubbo.configcenter.ConfigChangeEvent;
 import org.apache.dubbo.configcenter.ConfigChangeType;
 import org.apache.dubbo.configcenter.ConfigurationListener;
+import org.apache.dubbo.configcenter.DynamicConfiguration;
 
 import com.ctrip.framework.apollo.Config;
 import com.ctrip.framework.apollo.ConfigChangeListener;
@@ -34,28 +34,25 @@ import com.ctrip.framework.apollo.enums.PropertyChangeType;
 import com.ctrip.framework.apollo.model.ConfigChange;
 
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArraySet;
 
 /**
  * Apollo implementation, https://github.com/ctripcorp/apollo
  */
-public class ApolloDynamicConfiguration extends 
AbstractDynamicConfiguration<ApolloDynamicConfiguration.ApolloListener> {
+public class ApolloDynamicConfiguration implements DynamicConfiguration {
     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 URL url;
     private Config dubboConfig;
-
-    ApolloDynamicConfiguration() {
-    }
+    private ConcurrentMap<String, ApolloListener> listeners = new 
ConcurrentHashMap<>();
 
     ApolloDynamicConfiguration(URL url) {
-        super(url);
-    }
-
-    @Override
-    public void initWith(URL url) {
+        this.url = url;
         // Instead of using Dubbo's configuration, I would suggest use the 
original configuration method Apollo provides.
         String configEnv = url.getParameter(APOLLO_ENV_KEY);
         String configAddr = url.getBackupAddress();
@@ -86,12 +83,34 @@ public class ApolloDynamicConfiguration extends 
AbstractDynamicConfiguration<Apo
     }
 
     /**
+     * Since all governance rules will lay under dubbo group, this method now 
always uses the default dubboConfig and
+     * ignores the group parameter.
+     */
+    @Override
+    public void addListener(String key, String group, ConfigurationListener 
listener) {
+        ApolloListener apolloListener = listeners.computeIfAbsent(group + key, 
k -> createTargetListener(key, group));
+        apolloListener.addListener(listener);
+        dubboConfig.addChangeListener(apolloListener);
+    }
+
+    @Override
+    public void removeListener(String key, String group, ConfigurationListener 
listener) {
+        ApolloListener apolloListener = listeners.get(group + key);
+        if (apolloListener != null) {
+            apolloListener.removeListener(listener);
+            if (!apolloListener.hasInternalListener()) {
+                dubboConfig.removeChangeListener(apolloListener);
+            }
+        }
+    }
+
+    /**
      * This method will be used to:
      * 1. get configuration file at startup phase
      * 2. get all kinds of Dubbo rules
      */
     @Override
-    protected String getTargetConfig(String key, String group, long timeout) {
+    public String getConfig(String key, String group, long timeout) throws 
IllegalStateException {
         if (StringUtils.isNotEmpty(group) && 
!url.getParameter(Constants.CONFIG_GROUP_KEY, DEFAULT_GROUP).equals(group)) {
             Config config = ConfigService.getConfig(group);
             if (config != null) {
@@ -108,40 +127,19 @@ public class ApolloDynamicConfiguration extends 
AbstractDynamicConfiguration<Apo
      * But I think Apollo's inheritance feature of namespace can solve the 
problem .
      */
     @Override
-    protected String getInternalProperty(String key) {
+    public String getInternalProperty(String key) {
         return dubboConfig.getProperty(key, null);
     }
 
-    /**
-     * Since all governance rules will lay under dubbo group, this method now 
always uses the default dubboConfig and ignores the group parameter.
-     *
-     * @param key                   property key the native listener will 
listen on
-     * @param group                 to distinguish different set of properties
-     * @param listener
-     * @param configurationListener Listener in Dubbo that will handle 
notification.
-     */
-    @Override
-    protected void addConfigurationListener(String key, String group, 
ApolloListener listener, ConfigurationListener configurationListener) {
-        listener.addListener(configurationListener);
-        this.dubboConfig.addChangeListener(listener);
-    }
-
-    @Override
-    protected void removeConfigurationListener(String key, String group, 
ApolloListener listener, ConfigurationListener configurationListener) {
-        listener.removeListener(configurationListener);
-        if (!listener.hasInternalListener()) {
-            dubboConfig.removeChangeListener(listener);
-        }
-    }
 
     /**
      * Ignores the group parameter.
-     * @param key      property key the native listener will listen on
-     * @param group    to distinguish different set of properties
+     *
+     * @param key   property key the native listener will listen on
+     * @param group to distinguish different set of properties
      * @return
      */
-    @Override
-    protected ApolloListener createTargetListener(String key, String group) {
+    private ApolloListener createTargetListener(String key, String group) {
         return new ApolloListener();
     }
 
@@ -162,8 +160,10 @@ public class ApolloDynamicConfiguration extends 
AbstractDynamicConfiguration<Apo
                     return;
                 }
 
-                listeners.forEach(
-                        listener -> listener.process(new 
ConfigChangeEvent(key, change.getNewValue(), getChangeType(change)))
+                listeners.forEach(listener -> {
+                            ConfigChangeEvent event = new 
ConfigChangeEvent(key, change.getNewValue(), getChangeType(change));
+                            listener.process(event);
+                        }
                 );
             }
         }
@@ -175,15 +175,15 @@ public class ApolloDynamicConfiguration extends 
AbstractDynamicConfiguration<Apo
             return ConfigChangeType.MODIFIED;
         }
 
-        public void addListener(ConfigurationListener configurationListener) {
+        void addListener(ConfigurationListener configurationListener) {
             this.listeners.add(configurationListener);
         }
 
-        public void removeListener(ConfigurationListener 
configurationListener) {
+        void removeListener(ConfigurationListener configurationListener) {
             this.listeners.remove(configurationListener);
         }
 
-        public boolean hasInternalListener() {
+        boolean hasInternalListener() {
             return listeners != null && listeners.size() > 0;
         }
     }
diff --git 
a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
 
b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
index 1df548d..13cb911 100644
--- 
a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
+++ 
b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
@@ -20,8 +20,8 @@ import org.apache.dubbo.common.Constants;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.utils.NamedThreadFactory;
 import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.configcenter.AbstractDynamicConfiguration;
 import org.apache.dubbo.configcenter.ConfigurationListener;
+import org.apache.dubbo.configcenter.DynamicConfiguration;
 
 import org.apache.curator.RetryPolicy;
 import org.apache.curator.framework.CuratorFramework;
@@ -43,7 +43,7 @@ import static 
org.apache.dubbo.common.Constants.CONFIG_NAMESPACE_KEY;
 /**
  *
  */
-public class ZookeeperDynamicConfiguration extends 
AbstractDynamicConfiguration<CacheListener> {
+public class ZookeeperDynamicConfiguration implements DynamicConfiguration {
     private static final Logger logger = 
LoggerFactory.getLogger(ZookeeperDynamicConfiguration.class);
     private Executor executor;
     private CuratorFramework client;
@@ -54,15 +54,11 @@ public class ZookeeperDynamicConfiguration extends 
AbstractDynamicConfiguration<
     private CountDownLatch initializedLatch;
 
     private CacheListener cacheListener;
+    private URL url;
 
-    ZookeeperDynamicConfiguration() {
-    }
 
     ZookeeperDynamicConfiguration(URL url) {
-        super(url);
-    }
-
-    protected void initWith(URL url) {
+        this.url = url;
         rootPath = "/" + url.getParameter(CONFIG_NAMESPACE_KEY, DEFAULT_GROUP) 
+ "/config";
 
         RetryPolicy policy = new ExponentialBackoffRetry(1000, 3);
@@ -98,57 +94,47 @@ public class ZookeeperDynamicConfiguration extends 
AbstractDynamicConfiguration<
         }
     }
 
+    /**
+     * @param key e.g., {service}.configurators, {service}.tagrouters, 
{group}.dubbo.properties
+     * @return
+     */
     @Override
-    protected String getTargetConfig(String key, String group, long timeout) {
-        // when group is not null, we are getting startup configs from Config 
Center
-        // for example, group=dubbo, key=dubbo.properties
-        if (StringUtils.isNotEmpty(group)) {
-            key = group + "/" + key;
-        }
-        // when group is null, we are fetching governance rules.
-        // for example, key=org.apache.dubbo.DemoService.configurators
-        else {
-            int i = key.lastIndexOf(".");
-            key = key.substring(0, i) + "/" + key.substring(i + 1);
+    public Object getInternalProperty(String key) {
+        ChildData childData = treeCache.getCurrentData(key);
+        if (childData != null) {
+            return new String(childData.getData(), StandardCharsets.UTF_8);
         }
-
-        return (String) getInternalProperty(rootPath + "/" + key);
+        return null;
     }
 
     /**
      * For service governance, multi group is not supported by this 
implementation. So group is not used at present.
-     *
-     * @param key
-     * @param group
-     * @param cacheListener
-     * @param listener
      */
     @Override
-    protected void addConfigurationListener(String key, String group, 
CacheListener cacheListener, ConfigurationListener listener) {
+    public void addListener(String key, String group, ConfigurationListener 
listener) {
         cacheListener.addListener(key, listener);
     }
 
     @Override
-    protected void removeConfigurationListener(String key, String group, 
CacheListener cacheListener, ConfigurationListener configurationListener) {
-        cacheListener.removeListener(key, configurationListener);
+    public void removeListener(String key, String group, ConfigurationListener 
listener) {
+        cacheListener.removeListener(key, listener);
     }
 
     @Override
-    protected CacheListener createTargetListener(String key, String group) {
-        return cacheListener;
-    }
-
-    /**
-     * @param key e.g., {service}.configurators, {service}.tagrouters, 
{group}.dubbo.properties
-     * @return
-     */
-    @Override
-    protected Object getInternalProperty(String key) {
-        ChildData childData = treeCache.getCurrentData(key);
-        if (childData != null) {
-            return new String(childData.getData(), StandardCharsets.UTF_8);
+    public String getConfig(String key, String group, long timeout) throws 
IllegalStateException {
+        // when group is not null, we are getting startup configs from Config 
Center
+        // for example, group=dubbo, key=dubbo.properties
+        if (StringUtils.isNotEmpty(group)) {
+            key = group + "/" + key;
         }
-        return null;
+        // when group is null, we are fetching governance rules.
+        // for example, key=org.apache.dubbo.DemoService.configurators
+        else {
+            int i = key.lastIndexOf(".");
+            key = key.substring(0, i) + "/" + key.substring(i + 1);
+        }
+
+        return (String) getInternalProperty(rootPath + "/" + key);
     }
 
     /**

Reply via email to