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

kylixs pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.0 by this push:
     new 8891dd0  [3.0] Refactor MetricsConfig (#8785)
8891dd0 is described below

commit 8891dd0982ab7603fcec6f443f88100ff543c64a
Author: 吴治国 <[email protected]>
AuthorDate: Fri Sep 24 14:14:47 2021 +0800

    [3.0] Refactor MetricsConfig (#8785)
    
    * refactor metrics config and add empty prometheus implementation
    * Fix attribute name
---
 .../dubbo/common/constants/CommonConstants.java    |   4 -
 .../dubbo/common/constants/MetricsConstants.java   |  15 +-
 .../org/apache/dubbo/common/utils/FieldUtils.java  |   4 +-
 .../org/apache/dubbo/common/utils/MethodUtils.java |  32 ++++
 .../org/apache/dubbo/config/AbstractConfig.java    | 145 ++++++++++-----
 .../dubbo/config/AbstractInterfaceConfig.java      |  36 ++--
 .../org/apache/dubbo/config/MetricsConfig.java     |  79 ++++++--
 .../AggregationConfig.java}                        |  48 ++---
 .../dubbo/config/nested/PrometheusConfig.java      | 199 +++++++++++++++++++++
 .../org/apache/dubbo/config/support/Nested.java    |  22 ++-
 .../apache/dubbo/common/utils/MethodUtilsTest.java |  46 +++++
 .../dubbo/config/context/ConfigManagerTest.java    |   4 +-
 .../org/apache/dubbo/config/ReferenceConfig.java   |   2 +-
 .../org/apache/dubbo/config/ServiceConfig.java     |   3 +-
 .../apache/dubbo/config/AbstractConfigTest.java    |  69 +++++++
 .../org/apache/dubbo/config/MetricsConfigTest.java | 120 +++++++++++++
 .../apache/dubbo/config/ReferenceConfigTest.java   |  11 --
 .../dubbo/config/nested/AggregationConfigTest.java |  46 +++++
 .../dubbo/config/nested/PrometheusConfigTest.java  |  65 +++++++
 .../spring/schema/DubboBeanDefinitionParser.java   |  65 +++++++
 .../src/main/resources/META-INF/dubbo.xsd          | 109 ++++++++++-
 .../configprops/SpringBootConfigPropsTest.java     |  24 ++-
 .../SpringBootMultipleConfigPropsTest.java         |  59 +++---
 .../spring/schema/DubboNamespaceHandlerTest.java   |  58 ++++++
 .../dubbo/config/spring/metrics-aggregation.xml    |  31 ++++
 .../dubbo/config/spring/metrics-prometheus.xml     |  32 ++++
 dubbo-metrics/dubbo-metrics-api/pom.xml            |  39 ++++
 dubbo-metrics/dubbo-metrics-prometheus/pom.xml     |  39 ++++
 dubbo-metrics/pom.xml                              |  36 ++++
 .../org/apache/dubbo/monitor/MetricsService.java   |   5 +
 .../monitor/support/MetricsServiceDetector.java    |   5 +
 .../apache/dubbo/monitor/dubbo/MetricsFilter.java  |  10 +-
 .../dubbo/monitor/dubbo/MetricsFilterTest.java     |  20 +--
 .../DubboConfigurationProperties.java              |  22 +++
 pom.xml                                            |   1 +
 35 files changed, 1333 insertions(+), 172 deletions(-)

diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
index 8ca961e..06c222d 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
@@ -321,10 +321,6 @@ public interface CommonConstants {
 
     String EXPORTER_LISTENER_KEY = "exporter.listener";
 
-    String METRICS_PORT = "metrics.port";
-
-    String METRICS_PROTOCOL = "metrics.protocol";
-
     /**
      * After simplify the registry, should add some parameter individually for 
provider.
      *
diff --git 
a/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/support/MetricsServiceDetector.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java
similarity index 71%
copy from 
dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/support/MetricsServiceDetector.java
copy to 
dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java
index 3b9fa15..a8fd9a9 100644
--- 
a/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/support/MetricsServiceDetector.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java
@@ -14,16 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.monitor.support;
+package org.apache.dubbo.common.constants;
 
-import org.apache.dubbo.monitor.MetricsService;
-import org.apache.dubbo.rpc.model.BuiltinServiceDetector;
+public interface MetricsConstants {
 
-public class MetricsServiceDetector implements BuiltinServiceDetector {
+    String PROTOCOL_PROMETHEUS = "prometheus";
 
-    @Override
-    public Class<?> getService() {
-        return MetricsService.class;
-    }
+    String AGGREGATION_ENABLE = "aggregation.enable";
 
+    String AGGREGATION_BUCKET_NUM = "aggregation.bucket.num";
+
+    String AGGREGATION_TIME_WINDOW_SECONDS = "aggregation.time.window.seconds";
 }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/FieldUtils.java 
b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/FieldUtils.java
index 5c24ce1..394c726 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/FieldUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/FieldUtils.java
@@ -32,10 +32,10 @@ public interface FieldUtils {
      *
      * @param declaredClass the declared class
      * @param fieldName     the name of {@link Field}
-     * @return if can't be found, return <code>null</code>
+     * @return if field can't be found, return <code>null</code>
      */
     static Field getDeclaredField(Class<?> declaredClass, String fieldName) {
-        Field field = null;
+        Field field;
         try {
             field = declaredClass.getDeclaredField(fieldName);
         } catch (NoSuchFieldException ignored) {
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MethodUtils.java 
b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MethodUtils.java
index a885fb7..c8a0bbc 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MethodUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MethodUtils.java
@@ -21,6 +21,7 @@ import javax.lang.model.element.TypeElement;
 import javax.lang.model.util.Elements;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
@@ -395,4 +396,35 @@ public interface MethodUtils {
         List<Method> matchedMethods = getAllMethods(declaringClass, method -> 
overrides(overrider, method));
         return matchedMethods.isEmpty() ? null : matchedMethods.get(0);
     }
+
+    /**
+     * Extract fieldName from set/get/is method. if it's not a set/get/is 
method, return empty string.
+     * If method equals get/is/getClass/getObject, also return empty string.
+     *
+     * @param method method
+     * @return fieldName
+     */
+    static String extractFieldName(Method method) {
+        List<String> emptyFieldMethod = Arrays.asList("is", "get", 
"getObject", "getClass");
+        String methodName = method.getName();
+        String fieldName = "";
+
+        if (emptyFieldMethod.contains(methodName)) {
+            return fieldName;
+        } else if (methodName.startsWith("get")) {
+            fieldName = methodName.substring("get".length());
+        } else if (methodName.startsWith("set")) {
+            fieldName = methodName.substring("set".length());
+        } else if (methodName.startsWith("is")) {
+            fieldName = methodName.substring("is".length());
+        } else {
+            return fieldName;
+        }
+
+        if (StringUtils.isNotEmpty(fieldName)) {
+            fieldName = fieldName.substring(0, 1).toLowerCase() + 
fieldName.substring(1);
+        }
+
+        return fieldName;
+    }
 }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java 
b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
index 0f4186f..acceacb 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
@@ -26,10 +26,12 @@ import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.ClassUtils;
 import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.FieldUtils;
 import org.apache.dubbo.common.utils.MethodUtils;
 import org.apache.dubbo.common.utils.ReflectUtils;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.config.support.Nested;
 import org.apache.dubbo.config.support.Parameter;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.ModuleModel;
@@ -42,6 +44,7 @@ import java.beans.MethodDescriptor;
 import java.beans.PropertyDescriptor;
 import java.io.Serializable;
 import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
@@ -57,6 +60,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 
+import static org.apache.dubbo.common.utils.ClassUtils.isSimpleType;
 import static 
org.apache.dubbo.common.utils.ReflectUtils.findMethodByMethodSignature;
 import static org.apache.dubbo.config.Constants.PARAMETERS;
 
@@ -233,6 +237,11 @@ public abstract class AbstractConfig implements 
Serializable {
                             parameters.put(key, encodeParameters);
                         }
                     }
+                } else if (isNestedGetter(config, method)) {
+                    Object inner = method.invoke(config);
+                    String fieldName = MethodUtils.extractFieldName(method);
+                    String nestedPrefix = prefix == null ? fieldName : prefix 
+ "." + fieldName;
+                    appendParameters0(parameters, inner, nestedPrefix, 
asParameters);
                 }
             } catch (Exception e) {
                 throw new IllegalStateException("Append parameters failed: " + 
e.getMessage(), e);
@@ -302,6 +311,43 @@ public abstract class AbstractConfig implements 
Serializable {
             && method.getReturnType() == void.class);
     }
 
+    private static boolean isNestedGetter(Object obj, Method method) {
+        String name = method.getName();
+        boolean isGetter = (name.startsWith("get") || name.startsWith("is"))
+            && !"get".equals(name) && !"is".equals(name)
+            && !"getClass".equals(name) && !"getObject".equals(name)
+            && Modifier.isPublic(method.getModifiers())
+            && method.getParameterTypes().length == 0
+            && (!method.getReturnType().isPrimitive() && 
!isSimpleType(method.getReturnType()));
+
+        if (!isGetter) {
+            return false;
+        } else {
+            // Extract fieldName only when necessary.
+            String fieldName = MethodUtils.extractFieldName(method);
+            Field field = FieldUtils.getDeclaredField(obj.getClass(), 
fieldName);
+            return field != null && field.isAnnotationPresent(Nested.class);
+        }
+    }
+
+    private static boolean isNestedSetter(Object obj, Method method) {
+        boolean isSetter = method.getName().startsWith("set")
+            && !"set".equals(method.getName())
+            && Modifier.isPublic(method.getModifiers())
+            && method.getParameterCount() == 1
+            && method.getParameterTypes()[0] != null
+            && (!method.getParameterTypes()[0].isPrimitive() && 
!isSimpleType(method.getParameterTypes()[0]));
+
+        if (!isSetter) {
+            return false;
+        } else {
+            // Extract fieldName only when necessary.
+            String fieldName = MethodUtils.extractFieldName(method);
+            Field field = FieldUtils.getDeclaredField(obj.getClass(), 
fieldName);
+            return field != null && field.isAnnotationPresent(Nested.class);
+        }
+    }
+
     /**
      * @param parameters the raw parameters
      * @param prefix     the prefix
@@ -561,40 +607,7 @@ public abstract class AbstractConfig implements 
Serializable {
                     "], extracted props: " + subProperties);
             }
 
-            // loop methods, get override value and set the new value back to 
method
-            Method[] methods = getClass().getMethods();
-            for (Method method : methods) {
-                if (MethodUtils.isSetter(method)) {
-                    String propertyName = 
extractPropertyName(method.getName());
-                    // convert camelCase/snake_case to kebab-case
-                    String kebabPropertyName = 
StringUtils.convertToSplitName(propertyName, "-");
-
-                    try {
-                        String value = 
StringUtils.trim(subPropsConfiguration.getString(kebabPropertyName));
-                        // isTypeMatch() is called to avoid duplicate and 
incorrect update, for example, we have two 'setGeneric' methods in 
ReferenceConfig.
-                        if (StringUtils.hasText(value) && 
ClassUtils.isTypeMatch(method.getParameterTypes()[0], value) &&
-                            !isIgnoredAttribute(getClass(), propertyName)) {
-                            value = environment.resolvePlaceholders(value);
-                            method.invoke(this, 
ClassUtils.convertPrimitive(method.getParameterTypes()[0], value));
-                        }
-                    } catch (Exception e) {
-                        logger.info("Failed to override the property " + 
method.getName() + " in " +
-                            this.getClass().getSimpleName() +
-                            ", please make sure every property has 
getter/setter method provided.");
-                    }
-                } else if (isParametersSetter(method)) {
-                    String propertyName = 
extractPropertyName(method.getName());
-                    String value = 
StringUtils.trim(subPropsConfiguration.getString(propertyName));
-                    Map<String, String> parameterMap = null;
-                    if (StringUtils.hasText(value)) {
-                        parameterMap = StringUtils.parseParameters(value);
-                    } else {
-                        // in this case, maybe parameters.item3=value3.
-                        parameterMap = 
ConfigurationUtils.getSubProperties(subProperties, PARAMETERS);
-                    }
-                    invokeSetParameters(convert(parameterMap, ""));
-                }
-            }
+            assignProperties(this, environment, subProperties, 
subPropsConfiguration);
 
             // process extra refresh of sub class, e.g. refresh method configs
             processExtraRefresh(preferredPrefix, subPropsConfiguration);
@@ -607,17 +620,66 @@ public abstract class AbstractConfig implements 
Serializable {
         postProcessRefresh();
     }
 
-    private void invokeSetParameters(Map<String, String> values) {
+    private void assignProperties(Object obj, Environment environment, 
Map<String, String> properties, InmemoryConfiguration configuration) {
+        // loop methods, get override value and set the new value back to 
method
+        Method[] methods = obj.getClass().getMethods();
+        for (Method method : methods) {
+            if (MethodUtils.isSetter(method)) {
+                String propertyName = extractPropertyName(method.getName());
+                // convert camelCase/snake_case to kebab-case
+                String kebabPropertyName = 
StringUtils.convertToSplitName(propertyName, "-");
+
+                try {
+                    String value = 
StringUtils.trim(configuration.getString(kebabPropertyName));
+                    // isTypeMatch() is called to avoid duplicate and 
incorrect update, for example, we have two 'setGeneric' methods in 
ReferenceConfig.
+                    if (StringUtils.hasText(value) && 
ClassUtils.isTypeMatch(method.getParameterTypes()[0], value) &&
+                        !isIgnoredAttribute(obj.getClass(), propertyName)) {
+                        value = environment.resolvePlaceholders(value);
+                        method.invoke(obj, 
ClassUtils.convertPrimitive(method.getParameterTypes()[0], value));
+                    }
+                } catch (Exception e) {
+                    logger.info("Failed to override the property " + 
method.getName() + " in " +
+                        obj.getClass().getSimpleName() +
+                        ", please make sure every property has getter/setter 
method provided.");
+                }
+            } else if (isParametersSetter(method)) {
+                String propertyName = extractPropertyName(method.getName());
+                String value = 
StringUtils.trim(configuration.getString(propertyName));
+                Map<String, String> parameterMap = null;
+                if (StringUtils.hasText(value)) {
+                    parameterMap = StringUtils.parseParameters(value);
+                } else {
+                    // in this case, maybe parameters.item3=value3.
+                    parameterMap = 
ConfigurationUtils.getSubProperties(properties, PARAMETERS);
+                }
+                invokeSetParameters(convert(parameterMap, ""), obj);
+            } else if (isNestedSetter(obj, method)) {
+                try {
+                    Class<?> clazz = method.getParameterTypes()[0];
+                    Object inner = 
clazz.getDeclaredConstructor().newInstance();
+                    String fieldName = MethodUtils.extractFieldName(method);
+                    Map<String, String> subProperties = 
ConfigurationUtils.getSubProperties(properties, fieldName);
+                    InmemoryConfiguration subPropsConfiguration = new 
InmemoryConfiguration(subProperties);
+                    assignProperties(inner, environment, subProperties, 
subPropsConfiguration);
+                    method.invoke(obj, inner);
+                } catch (ReflectiveOperationException e) {
+                    throw new IllegalStateException("Cannot assign nested 
class when refreshing config: " + obj.getClass().getName(), e);
+                }
+            }
+        }
+    }
+
+    private void invokeSetParameters(Map<String, String> values, Object obj) {
         if (CollectionUtils.isEmptyMap(values)) {
             return;
         }
-        Map<String, String> map = invokeGetParameters(getClass(), this);
+        Map<String, String> map = invokeGetParameters(obj.getClass(), obj);
         map = map == null ? new HashMap<>() : map;
         map.putAll(values);
-        invokeSetParameters(getClass(), this, map);
+        invokeSetParameters(obj.getClass(), obj, map);
     }
 
-    private boolean isIgnoredAttribute(Class<? extends AbstractConfig> clazz, 
String propertyName) {
+    private boolean isIgnoredAttribute(Class<?> clazz, String propertyName) {
         Method getter = null;
         String capitalizePropertyName = propertyName.substring(0, 
1).toUpperCase() + propertyName.substring(1);
         try {
@@ -635,11 +697,8 @@ public abstract class AbstractConfig implements 
Serializable {
         }
 
         Parameter parameter = getter.getAnnotation(Parameter.class);
-        if (parameter != null && !parameter.attribute()) {
-            // not an attribute
-            return true;
-        }
-        return false;
+        // not an attribute
+        return parameter != null && !parameter.attribute();
     }
 
     protected void processExtraRefresh(String preferredPrefix, 
InmemoryConfiguration subPropsConfiguration) {
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
index 034de91..edf769c 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
@@ -51,6 +51,7 @@ import static 
org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER
 import static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
+import static 
org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;
 
 
 /**
@@ -173,7 +174,6 @@ public abstract class AbstractInterfaceConfig extends 
AbstractMethodConfig {
     /**
      * The metrics configuration
      */
-    protected MetricsConfig metrics;
     protected MetadataReportConfig metadataReportConfig;
 
     protected ConfigCenterConfig configCenter;
@@ -221,9 +221,6 @@ public abstract class AbstractInterfaceConfig extends 
AbstractMethodConfig {
         if (this.metadataReportConfig != null && 
this.metadataReportConfig.getScopeModel() != applicationModel) {
             this.metadataReportConfig.setScopeModel(applicationModel);
         }
-        if (this.metrics != null && this.metrics.getScopeModel() != 
applicationModel) {
-            this.metrics.setScopeModel(applicationModel);
-        }
         if (this.monitor != null && this.monitor.getScopeModel() != 
applicationModel) {
             this.monitor.setScopeModel(applicationModel);
         }
@@ -263,6 +260,21 @@ public abstract class AbstractInterfaceConfig extends 
AbstractMethodConfig {
     }
 
     /**
+     * @deprecated After metrics config is refactored.
+     * This method should no longer use and will be deleted in the future.
+     */
+    @Deprecated
+    protected void appendMetricsCompatible(Map<String, String> map) {
+        MetricsConfig metricsConfig = 
getConfigManager().getMetrics().orElse(null);
+        if (metricsConfig != null) {
+            if (!metricsConfig.getProtocol().equals(PROTOCOL_PROMETHEUS)) {
+                map.put("metrics.protocol", metricsConfig.getProtocol());
+                map.put("metrics.port", metricsConfig.getPort());
+            }
+        }
+    }
+
+    /**
      * To obtain the method list in the port, use reflection when in native 
mode and javaassist otherwise.
      * @param interfaceClass
      * @return
@@ -781,22 +793,6 @@ public abstract class AbstractInterfaceConfig extends 
AbstractMethodConfig {
         }
     }
 
-    @Deprecated
-    public MetricsConfig getMetrics() {
-        if (metrics != null) {
-            return metrics;
-        }
-        return getConfigManager().getMetrics().orElse(null);
-    }
-
-    @Deprecated
-    public void setMetrics(MetricsConfig metrics) {
-        this.metrics = metrics;
-        if (metrics != null) {
-            getConfigManager().setMetrics(metrics);
-        }
-    }
-
     @Parameter(key = TAG_KEY)
     public String getTag() {
         return tag;
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java 
b/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java
index ae41a62..f9a3c75 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java
@@ -14,25 +14,75 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.dubbo.config;
 
-import org.apache.dubbo.config.support.Parameter;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.common.utils.UrlUtils;
+import org.apache.dubbo.config.nested.AggregationConfig;
+import org.apache.dubbo.config.nested.PrometheusConfig;
+import org.apache.dubbo.config.support.Nested;
+
+import java.util.HashMap;
+import java.util.Map;
 
-import static org.apache.dubbo.common.constants.CommonConstants.METRICS_PORT;
-import static 
org.apache.dubbo.common.constants.CommonConstants.METRICS_PROTOCOL;
+import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
+import static 
org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;
 
+/**
+ * MetricsConfig
+ */
 public class MetricsConfig extends AbstractConfig {
 
     private static final long serialVersionUID = -9089919311611546383L;
 
-    private String port;
     private String protocol;
 
+    /**
+     * @deprecated After metrics config is refactored.
+     * This parameter should no longer use and will be deleted in the future.
+     */
+    @Deprecated
+    private String port;
+
+    /**
+     * The prometheus metrics config
+     */
+    @Nested
+    private PrometheusConfig prometheus;
+
+    /**
+     * The metrics aggregation config
+     */
+    @Nested
+    private AggregationConfig aggregation;
+
     public MetricsConfig() {
+        super();
+    }
+
+    public URL toUrl() {
+        Map<String, String> map = new HashMap<>();
+        appendParameters(map, this);
+
+        // use 'prometheus' as the default metrics service.
+        if (StringUtils.isEmpty(map.get(PROTOCOL_KEY))) {
+            map.put(PROTOCOL_KEY, PROTOCOL_PROMETHEUS);
+        }
+
+        // ignore address parameter, use specified url in each metrics server 
config
+        // the address "localhost" here is meaningless
+        return UrlUtils.parseURL("localhost", map);
+    }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
     }
 
-    @Parameter(key = METRICS_PORT)
     public String getPort() {
         return port;
     }
@@ -41,13 +91,20 @@ public class MetricsConfig extends AbstractConfig {
         this.port = port;
     }
 
-    @Parameter(key = METRICS_PROTOCOL)
-    public String getProtocol() {
-        return protocol;
+    public PrometheusConfig getPrometheus() {
+        return prometheus;
     }
 
-    public void setProtocol(String protocol) {
-        this.protocol = protocol;
+    public void setPrometheus(PrometheusConfig prometheus) {
+        this.prometheus = prometheus;
     }
 
+    public AggregationConfig getAggregation() {
+        return aggregation;
+    }
+
+    public void setAggregation(AggregationConfig aggregation) {
+        this.aggregation = aggregation;
+    }
 }
+
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java 
b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/AggregationConfig.java
similarity index 50%
copy from dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java
copy to 
dubbo-common/src/main/java/org/apache/dubbo/config/nested/AggregationConfig.java
index ae41a62..da0a6ce 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/AggregationConfig.java
@@ -14,40 +14,46 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.dubbo.config.nested;
 
-package org.apache.dubbo.config;
+public class AggregationConfig {
 
-import org.apache.dubbo.config.support.Parameter;
+    /**
+     * Enable local aggregation or not
+     */
+    private Boolean enabled;
 
-import static org.apache.dubbo.common.constants.CommonConstants.METRICS_PORT;
-import static 
org.apache.dubbo.common.constants.CommonConstants.METRICS_PROTOCOL;
+    /**
+     * Bucket num for time window quantile
+     */
+    private Integer bucketNum;
 
-public class MetricsConfig extends AbstractConfig {
+    /**
+     * Time window seconds for time window quantile
+     */
+    private Integer timeWindowSeconds;
 
-    private static final long serialVersionUID = -9089919311611546383L;
-
-    private String port;
-    private String protocol;
-
-    public MetricsConfig() {
+    public Boolean getEnabled() {
+        return enabled;
     }
 
-    @Parameter(key = METRICS_PORT)
-    public String getPort() {
-        return port;
+    public void setEnabled(Boolean enabled) {
+        this.enabled = enabled;
     }
 
-    public void setPort(String port) {
-        this.port = port;
+    public Integer getBucketNum() {
+        return bucketNum;
     }
 
-    @Parameter(key = METRICS_PROTOCOL)
-    public String getProtocol() {
-        return protocol;
+    public void setBucketNum(Integer bucketNum) {
+        this.bucketNum = bucketNum;
     }
 
-    public void setProtocol(String protocol) {
-        this.protocol = protocol;
+    public Integer getTimeWindowSeconds() {
+        return timeWindowSeconds;
     }
 
+    public void setTimeWindowSeconds(Integer timeWindowSeconds) {
+        this.timeWindowSeconds = timeWindowSeconds;
+    }
 }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/PrometheusConfig.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/PrometheusConfig.java
new file mode 100644
index 0000000..98da33c
--- /dev/null
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/PrometheusConfig.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.nested;
+
+import org.apache.dubbo.config.support.Nested;
+
+public class PrometheusConfig {
+
+    /**
+     * Prometheus exporter configuration
+     */
+    @Nested
+    private Exporter exporter;
+
+    /**
+     * Prometheus Pushgateway configuration
+     */
+    @Nested
+    private Pushgateway pushgateway;
+
+    public Exporter getExporter() {
+        return exporter;
+    }
+
+    public void setExporter(Exporter exporter) {
+        this.exporter = exporter;
+    }
+
+    public Pushgateway getPushgateway() {
+        return pushgateway;
+    }
+
+    public void setPushgateway(Pushgateway pushgateway) {
+        this.pushgateway = pushgateway;
+    }
+
+    public static class Exporter {
+
+        /**
+         * Enable prometheus exporter
+         */
+        private Boolean enabled;
+
+        /**
+         * Enable http service discovery for prometheus
+         */
+        private Boolean enableHttpServiceDiscovery;
+
+        /**
+         * Http service discovery url
+         */
+        private String httpServiceDiscoveryUrl;
+
+        /**
+         * When using pull method, which port to expose
+         */
+        private Integer metricsPort;
+
+        /**
+         * When using pull mode, which path to expose metrics
+         */
+        private String metricsPath;
+
+        public Boolean getEnabled() {
+            return enabled;
+        }
+
+        public void setEnabled(Boolean enabled) {
+            this.enabled = enabled;
+        }
+
+        public Boolean getEnableHttpServiceDiscovery() {
+            return enableHttpServiceDiscovery;
+        }
+
+        public void setEnableHttpServiceDiscovery(Boolean 
enableHttpServiceDiscovery) {
+            this.enableHttpServiceDiscovery = enableHttpServiceDiscovery;
+        }
+
+        public String getHttpServiceDiscoveryUrl() {
+            return httpServiceDiscoveryUrl;
+        }
+
+        public void setHttpServiceDiscoveryUrl(String httpServiceDiscoveryUrl) 
{
+            this.httpServiceDiscoveryUrl = httpServiceDiscoveryUrl;
+        }
+
+        public Integer getMetricsPort() {
+            return metricsPort;
+        }
+
+        public void setMetricsPort(Integer metricsPort) {
+            this.metricsPort = metricsPort;
+        }
+
+        public String getMetricsPath() {
+            return metricsPath;
+        }
+
+        public void setMetricsPath(String metricsPath) {
+            this.metricsPath = metricsPath;
+        }
+    }
+
+    public static class Pushgateway {
+
+        /**
+         * Enable publishing via a Prometheus Pushgateway
+         */
+        private Boolean enabled;
+
+        /**
+         * Base URL for the Pushgateway
+         */
+        private String baseUrl;
+
+        /**
+         * Login user of the Prometheus Pushgateway
+         */
+        private String username;
+
+        /**
+         * Login password of the Prometheus Pushgateway
+         */
+        private String password;
+
+        /**
+         * Frequency with which to push metrics
+         */
+        private Integer pushInterval;
+
+        /**
+         * Job identifier for this application instance
+         */
+        private String job;
+
+        public Boolean getEnabled() {
+            return enabled;
+        }
+
+        public void setEnabled(Boolean enabled) {
+            this.enabled = enabled;
+        }
+
+        public String getBaseUrl() {
+            return baseUrl;
+        }
+
+        public void setBaseUrl(String baseUrl) {
+            this.baseUrl = baseUrl;
+        }
+
+        public String getUsername() {
+            return username;
+        }
+
+        public void setUsername(String username) {
+            this.username = username;
+        }
+
+        public String getPassword() {
+            return password;
+        }
+
+        public void setPassword(String password) {
+            this.password = password;
+        }
+
+        public Integer getPushInterval() {
+            return pushInterval;
+        }
+
+        public void setPushInterval(Integer pushInterval) {
+            this.pushInterval = pushInterval;
+        }
+
+        public String getJob() {
+            return job;
+        }
+
+        public void setJob(String job) {
+            this.job = job;
+        }
+    }
+}
diff --git 
a/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/support/MetricsServiceDetector.java
 b/dubbo-common/src/main/java/org/apache/dubbo/config/support/Nested.java
similarity index 67%
copy from 
dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/support/MetricsServiceDetector.java
copy to dubbo-common/src/main/java/org/apache/dubbo/config/support/Nested.java
index 3b9fa15..1cab41a 100644
--- 
a/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/support/MetricsServiceDetector.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/support/Nested.java
@@ -14,16 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.monitor.support;
+package org.apache.dubbo.config.support;
 
-import org.apache.dubbo.monitor.MetricsService;
-import org.apache.dubbo.rpc.model.BuiltinServiceDetector;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
-public class MetricsServiceDetector implements BuiltinServiceDetector {
-
-    @Override
-    public Class<?> getService() {
-        return MetricsService.class;
-    }
+/**
+ * Nested Class Parameter
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface Nested {
 
 }
diff --git 
a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MethodUtilsTest.java 
b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MethodUtilsTest.java
index e8eb7f1..c174b68 100644
--- 
a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MethodUtilsTest.java
+++ 
b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MethodUtilsTest.java
@@ -96,6 +96,52 @@ public class MethodUtilsTest {
 
     }
 
+    @Test
+    public void testExtractFieldName() throws Exception {
+        Method m1 = MethodFieldTestClazz.class.getMethod("is");
+        Method m2 = MethodFieldTestClazz.class.getMethod("get");
+        Method m3 = MethodFieldTestClazz.class.getMethod("getClass");
+        Method m4 = MethodFieldTestClazz.class.getMethod("getObject");
+        Method m5 = MethodFieldTestClazz.class.getMethod("getFieldName1");
+        Method m6 = MethodFieldTestClazz.class.getMethod("setFieldName2");
+        Method m7 = MethodFieldTestClazz.class.getMethod("isFieldName3");
+
+        Assertions.assertEquals("", MethodUtils.extractFieldName(m1));
+        Assertions.assertEquals("", MethodUtils.extractFieldName(m2));
+        Assertions.assertEquals("", MethodUtils.extractFieldName(m3));
+        Assertions.assertEquals("", MethodUtils.extractFieldName(m4));
+        Assertions.assertEquals("fieldName1", 
MethodUtils.extractFieldName(m5));
+        Assertions.assertEquals("fieldName2", 
MethodUtils.extractFieldName(m6));
+        Assertions.assertEquals("fieldName3", 
MethodUtils.extractFieldName(m7));
+    }
+
+    public class MethodFieldTestClazz {
+        public String is() {
+            return "";
+        }
+
+        public String get() {
+            return "";
+        }
+
+        public String getObject() {
+            return "";
+        }
+
+        public String getFieldName1() {
+            return "";
+        }
+
+        public String setFieldName2() {
+            return "";
+        }
+
+        public String isFieldName3() {
+            return "";
+        }
+
+    }
+
     public class MethodTestClazz {
         private String value;
 
diff --git 
a/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
 
b/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
index 0abcbb9..bf298b3 100644
--- 
a/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
+++ 
b/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
@@ -34,6 +34,7 @@ import java.util.Collection;
 
 import static java.util.Arrays.asList;
 import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;
+import static 
org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;
 import static org.apache.dubbo.config.context.ConfigManager.DUBBO_CONFIG_MODE;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -127,8 +128,9 @@ public class ConfigManagerTest {
 
     // Test MetricsConfig correlative methods
     @Test
-    public void tesMetricsConfig() {
+    public void testMetricsConfig() {
         MetricsConfig config = new MetricsConfig();
+        config.setProtocol(PROTOCOL_PROMETHEUS);
         configManager.setMetrics(config);
         assertTrue(configManager.getMetrics().isPresent());
         assertEquals(config, configManager.getMetrics().get());
diff --git 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
index 6f3127e..d005e38 100644
--- 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
+++ 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
@@ -325,11 +325,11 @@ public class ReferenceConfig<T> extends 
ReferenceConfigBase<T> {
             }
         }
 
-        AbstractConfig.appendParameters(map, getMetrics());
         AbstractConfig.appendParameters(map, getApplication());
         AbstractConfig.appendParameters(map, getModule());
         AbstractConfig.appendParameters(map, consumer);
         AbstractConfig.appendParameters(map, this);
+        appendMetricsCompatible(map);
 
         MetadataReportConfig metadataReportConfig = getMetadataReportConfig();
         if (metadataReportConfig != null && metadataReportConfig.isValid()) {
diff --git 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
index 045625b..5cb250c 100644
--- 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
+++ 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
@@ -422,7 +422,6 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
 
         // append params with basic configs,
         ServiceConfig.appendRuntimeParameters(map);
-        AbstractConfig.appendParameters(map, getMetrics());
         AbstractConfig.appendParameters(map, getApplication());
         AbstractConfig.appendParameters(map, getModule());
         // remove 'default.' prefix for configs from ProviderConfig
@@ -430,6 +429,8 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
         AbstractConfig.appendParameters(map, provider);
         AbstractConfig.appendParameters(map, protocolConfig);
         AbstractConfig.appendParameters(map, this);
+        appendMetricsCompatible(map);
+
         MetadataReportConfig metadataReportConfig = getMetadataReportConfig();
         if (metadataReportConfig != null && metadataReportConfig.isValid()) {
             map.putIfAbsent(METADATA_KEY, REMOTE_METADATA_STORAGE_TYPE);
diff --git 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java
 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java
index ef6f76f..4112db7 100644
--- 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java
+++ 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java
@@ -19,6 +19,7 @@ package org.apache.dubbo.config;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.api.Greeting;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.config.support.Nested;
 import org.apache.dubbo.config.support.Parameter;
 import org.apache.dubbo.config.utils.ConfigValidationUtils;
 import org.apache.dubbo.rpc.model.ApplicationModel;
@@ -940,4 +941,72 @@ public class AbstractConfigTest {
             System.out.println(configClass.getSimpleName()+" metadata is 
checked.");
         }
     }
+
+    @Test
+    public void testRefreshNested() {
+        try {
+            OuterConfig outerConfig = new OuterConfig();
+
+            Map<String, String> external = new HashMap<>();
+            external.put("dubbo.outer.a1", "1");
+            external.put("dubbo.outer.b.b1", "11");
+            external.put("dubbo.outer.b.b2", "12");
+            ApplicationModel.defaultModel().getModelEnvironment().initialize();
+            
ApplicationModel.defaultModel().getModelEnvironment().setExternalConfigMap(external);
+
+            // refresh config
+            outerConfig.refresh();
+
+            Assertions.assertEquals(1, outerConfig.getA1());
+            Assertions.assertEquals(11, outerConfig.getB().getB1());
+            Assertions.assertEquals(12, outerConfig.getB().getB2());
+        } finally {
+            ApplicationModel.defaultModel().getModelEnvironment().destroy();
+        }
+    }
+
+    private static class OuterConfig extends AbstractConfig {
+        private Integer a1;
+
+        @Nested
+        private InnerConfig b;
+
+        public Integer getA1() {
+            return a1;
+        }
+
+        public void setA1(Integer a1) {
+            this.a1 = a1;
+        }
+
+        public InnerConfig getB() {
+            return b;
+        }
+
+        public void setB(InnerConfig b) {
+            this.b = b;
+        }
+    }
+
+    public static class InnerConfig {
+        private Integer b1;
+
+        private Integer b2;
+
+        public Integer getB1() {
+            return b1;
+        }
+
+        public void setB1(Integer b1) {
+            this.b1 = b1;
+        }
+
+        public Integer getB2() {
+            return b2;
+        }
+
+        public void setB2(Integer b2) {
+            this.b2 = b2;
+        }
+    }
 }
diff --git 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MetricsConfigTest.java
 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MetricsConfigTest.java
new file mode 100644
index 0000000..ed6fd87
--- /dev/null
+++ 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MetricsConfigTest.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.config.nested.AggregationConfig;
+import org.apache.dubbo.config.nested.PrometheusConfig;
+
+import org.junit.jupiter.api.Test;
+
+import static 
org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+
+public class MetricsConfigTest {
+
+    @Test
+    public void testToUrl() {
+        MetricsConfig metrics = new MetricsConfig();
+        metrics.setProtocol(PROTOCOL_PROMETHEUS);
+
+        PrometheusConfig prometheus = new PrometheusConfig();
+        PrometheusConfig.Exporter exporter = new PrometheusConfig.Exporter();
+        PrometheusConfig.Pushgateway pushgateway = new 
PrometheusConfig.Pushgateway();
+
+        exporter.setEnabled(true);
+        pushgateway.setEnabled(true);
+        prometheus.setExporter(exporter);
+        prometheus.setPushgateway(pushgateway);
+        metrics.setPrometheus(prometheus);
+
+        AggregationConfig aggregation = new AggregationConfig();
+        aggregation.setEnabled(true);
+        metrics.setAggregation(aggregation);
+
+        URL url = metrics.toUrl();
+
+        assertThat(url.getProtocol(), equalTo(PROTOCOL_PROMETHEUS));
+        assertThat(url.getAddress(), equalTo("localhost:9090"));
+        assertThat(url.getHost(), equalTo("localhost"));
+        assertThat(url.getPort(), equalTo(9090));
+        assertThat(url.getParameter("prometheus.exporter.enabled"), 
equalTo("true"));
+        assertThat(url.getParameter("prometheus.pushgateway.enabled"), 
equalTo("true"));
+        assertThat(url.getParameter("aggregation.enabled"), equalTo("true"));
+    }
+
+    @Test
+    public void testProtocol() {
+        MetricsConfig metrics = new MetricsConfig();
+        metrics.setProtocol(PROTOCOL_PROMETHEUS);
+        assertThat(metrics.getProtocol(), equalTo(PROTOCOL_PROMETHEUS));
+    }
+
+    @Test
+    public void testPrometheus() {
+        MetricsConfig metrics = new MetricsConfig();
+
+        PrometheusConfig prometheus = new PrometheusConfig();
+        PrometheusConfig.Exporter exporter = new PrometheusConfig.Exporter();
+        PrometheusConfig.Pushgateway pushgateway = new 
PrometheusConfig.Pushgateway();
+
+        exporter.setEnabled(true);
+        exporter.setEnableHttpServiceDiscovery(true);
+        exporter.setHttpServiceDiscoveryUrl("localhost:8080");
+        exporter.setMetricsPath("/metrics");
+        exporter.setMetricsPort(20888);
+        prometheus.setExporter(exporter);
+
+        pushgateway.setEnabled(true);
+        pushgateway.setBaseUrl("localhost:9091");
+        pushgateway.setUsername("username");
+        pushgateway.setPassword("password");
+        pushgateway.setJob("job");
+        pushgateway.setPushInterval(30);
+        prometheus.setPushgateway(pushgateway);
+
+        metrics.setPrometheus(prometheus);
+
+        assertThat(metrics.getPrometheus().getExporter().getEnabled(), 
equalTo(true));
+        
assertThat(metrics.getPrometheus().getExporter().getEnableHttpServiceDiscovery(),
 equalTo(true));
+        
assertThat(metrics.getPrometheus().getExporter().getHttpServiceDiscoveryUrl(), 
equalTo("localhost:8080"));
+        assertThat(metrics.getPrometheus().getExporter().getMetricsPort(), 
equalTo(20888));
+        assertThat(metrics.getPrometheus().getExporter().getMetricsPath(), 
equalTo("/metrics"));
+        assertThat(metrics.getPrometheus().getPushgateway().getEnabled(), 
equalTo(true));
+        assertThat(metrics.getPrometheus().getPushgateway().getBaseUrl(), 
equalTo("localhost:9091"));
+        assertThat(metrics.getPrometheus().getPushgateway().getUsername(), 
equalTo("username"));
+        assertThat(metrics.getPrometheus().getPushgateway().getPassword(), 
equalTo("password"));
+        assertThat(metrics.getPrometheus().getPushgateway().getJob(), 
equalTo("job"));
+        assertThat(metrics.getPrometheus().getPushgateway().getPushInterval(), 
equalTo(30));
+    }
+
+    @Test
+    public void testAggregation() {
+        MetricsConfig metrics = new MetricsConfig();
+
+        AggregationConfig aggregation = new AggregationConfig();
+        aggregation.setEnabled(true);
+        aggregation.setBucketNum(5);
+        aggregation.setTimeWindowSeconds(120);
+        metrics.setAggregation(aggregation);
+
+        assertThat(metrics.getAggregation().getEnabled(), equalTo(true));
+        assertThat(metrics.getAggregation().getBucketNum(), equalTo(5));
+        assertThat(metrics.getAggregation().getTimeWindowSeconds(), 
equalTo(120));
+    }
+}
diff --git 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
index 09c07dd..5f094b0 100644
--- 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
+++ 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
@@ -92,8 +92,6 @@ import static 
org.apache.dubbo.common.constants.CommonConstants.LIVENESS_PROBE_K
 import static org.apache.dubbo.common.constants.CommonConstants.METADATA_KEY;
 import static 
org.apache.dubbo.common.constants.CommonConstants.METADATA_SERVICE_PORT_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.METRICS_PORT;
-import static 
org.apache.dubbo.common.constants.CommonConstants.METRICS_PROTOCOL;
 import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
 import static 
org.apache.dubbo.common.constants.CommonConstants.READINESS_PROBE_KEY;
 import static 
org.apache.dubbo.common.constants.CommonConstants.REFER_ASYNC_KEY;
@@ -212,10 +210,6 @@ public class ReferenceConfigTest {
         MonitorConfig monitorConfig = new MonitorConfig();
         applicationConfig.setMonitor(monitorConfig);
 
-        MetricsConfig metricsConfig = new MetricsConfig();
-        metricsConfig.setProtocol("metricProtocol");
-        metricsConfig.setPort("55555");
-
         ModuleConfig moduleConfig = new ModuleConfig();
         moduleConfig.setMonitor("default");
         moduleConfig.setName("module1");
@@ -264,7 +258,6 @@ public class ReferenceConfigTest {
         dubboBootstrap.application(applicationConfig)
             .reference(referenceConfig)
             .registry(registry)
-            .metrics(metricsConfig)
             .module(moduleConfig)
             .initialize();
 
@@ -290,10 +283,6 @@ public class ReferenceConfigTest {
         
Assertions.assertTrue(serviceMetadata.getAttachments().containsKey(TIMESTAMP_KEY));
         Assertions.assertEquals(String.valueOf(ConfigUtils.getPid()), 
serviceMetadata.getAttachments().get(PID_KEY));
 
-        // verify additional metric config
-        Assertions.assertEquals(metricsConfig.getProtocol(), 
serviceMetadata.getAttachments().get(METRICS_PROTOCOL));
-        Assertions.assertEquals(metricsConfig.getPort(), 
serviceMetadata.getAttachments().get(METRICS_PORT));
-
         // verify additional application config
         Assertions.assertEquals(applicationConfig.getName(), 
serviceMetadata.getAttachments().get(APPLICATION_KEY));
         Assertions.assertEquals(applicationConfig.getOwner(), 
serviceMetadata.getAttachments().get("owner"));
diff --git 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/nested/AggregationConfigTest.java
 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/nested/AggregationConfigTest.java
new file mode 100644
index 0000000..b24f49c
--- /dev/null
+++ 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/nested/AggregationConfigTest.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.config.nested;
+
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+
+public class AggregationConfigTest {
+
+    @Test
+    public void testEnabled() {
+        AggregationConfig aggregationConfig = new AggregationConfig();
+        aggregationConfig.setEnabled(true);
+        assertThat(aggregationConfig.getEnabled(), equalTo(true));
+    }
+
+    @Test
+    public void testBucketNum() {
+        AggregationConfig aggregationConfig = new AggregationConfig();
+        aggregationConfig.setBucketNum(5);
+        assertThat(aggregationConfig.getBucketNum(), equalTo(5));
+    }
+
+    @Test
+    public void testTimeWindowSeconds() {
+        AggregationConfig aggregationConfig = new AggregationConfig();
+        aggregationConfig.setTimeWindowSeconds(120);
+        assertThat(aggregationConfig.getTimeWindowSeconds(), equalTo(120));
+    }
+}
diff --git 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/nested/PrometheusConfigTest.java
 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/nested/PrometheusConfigTest.java
new file mode 100644
index 0000000..7dc3518
--- /dev/null
+++ 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/nested/PrometheusConfigTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.nested;
+
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+
+public class PrometheusConfigTest {
+
+    @Test
+    public void testExporter() {
+        PrometheusConfig prometheusConfig = new PrometheusConfig();
+        PrometheusConfig.Exporter exporter = new PrometheusConfig.Exporter();
+
+        exporter.setEnabled(true);
+        exporter.setEnableHttpServiceDiscovery(true);
+        exporter.setHttpServiceDiscoveryUrl("localhost:8080");
+        exporter.setMetricsPath("/metrics");
+        exporter.setMetricsPort(20888);
+        prometheusConfig.setExporter(exporter);
+
+        assertThat(prometheusConfig.getExporter().getEnabled(), equalTo(true));
+        
assertThat(prometheusConfig.getExporter().getEnableHttpServiceDiscovery(), 
equalTo(true));
+        
assertThat(prometheusConfig.getExporter().getHttpServiceDiscoveryUrl(), 
equalTo("localhost:8080"));
+        assertThat(prometheusConfig.getExporter().getMetricsPort(), 
equalTo(20888));
+        assertThat(prometheusConfig.getExporter().getMetricsPath(), 
equalTo("/metrics"));
+    }
+
+    @Test
+    public void testPushgateway() {
+        PrometheusConfig prometheusConfig = new PrometheusConfig();
+        PrometheusConfig.Pushgateway pushgateway = new 
PrometheusConfig.Pushgateway();
+
+        pushgateway.setEnabled(true);
+        pushgateway.setBaseUrl("localhost:9091");
+        pushgateway.setUsername("username");
+        pushgateway.setPassword("password");
+        pushgateway.setJob("job");
+        pushgateway.setPushInterval(30);
+        prometheusConfig.setPushgateway(pushgateway);
+
+        assertThat(prometheusConfig.getPushgateway().getEnabled(), 
equalTo(true));
+        assertThat(prometheusConfig.getPushgateway().getBaseUrl(), 
equalTo("localhost:9091"));
+        assertThat(prometheusConfig.getPushgateway().getUsername(), 
equalTo("username"));
+        assertThat(prometheusConfig.getPushgateway().getPassword(), 
equalTo("password"));
+        assertThat(prometheusConfig.getPushgateway().getJob(), equalTo("job"));
+        assertThat(prometheusConfig.getPushgateway().getPushInterval(), 
equalTo(30));
+    }
+}
diff --git 
a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java
 
b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java
index a28b497..a146590 100644
--- 
a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java
+++ 
b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java
@@ -18,20 +18,26 @@ package org.apache.dubbo.config.spring.schema;
 
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.ClassUtils;
+import org.apache.dubbo.common.utils.MethodUtils;
 import org.apache.dubbo.common.utils.ReflectUtils;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.AbstractServiceConfig;
 import org.apache.dubbo.config.ArgumentConfig;
 import org.apache.dubbo.config.ConsumerConfig;
 import org.apache.dubbo.config.MethodConfig;
+import org.apache.dubbo.config.MetricsConfig;
 import org.apache.dubbo.config.ProtocolConfig;
 import org.apache.dubbo.config.ProviderConfig;
 import org.apache.dubbo.config.ReferenceConfig;
 import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.nested.AggregationConfig;
+import org.apache.dubbo.config.nested.PrometheusConfig;
 import org.apache.dubbo.config.spring.Constants;
 import org.apache.dubbo.config.spring.ReferenceBean;
 import org.apache.dubbo.config.spring.ServiceBean;
 import org.apache.dubbo.config.spring.reference.ReferenceAttributes;
+
 import org.springframework.beans.PropertyValue;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.config.BeanDefinitionHolder;
@@ -49,6 +55,7 @@ import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.Date;
@@ -229,6 +236,8 @@ public class DubboBeanDefinitionParser implements 
BeanDefinitionParser {
             parseNested(element, parserContext, ReferenceBean.class, true, 
"reference", "consumer", beanName, beanDefinition);
         } else if (ReferenceBean.class.equals(beanClass)) {
             configReferenceBean(element, parserContext, beanDefinition, null);
+        } else if (MetricsConfig.class.equals(beanClass)) {
+            parseMetrics(element, parserContext, beanDefinition);
         }
 
         // register bean definition
@@ -242,6 +251,62 @@ public class DubboBeanDefinitionParser implements 
BeanDefinitionParser {
         return beanDefinition;
     }
 
+    private static void parseMetrics(Element element, ParserContext 
parserContext, RootBeanDefinition beanDefinition) {
+        NodeList childNodes = element.getChildNodes();
+        PrometheusConfig prometheus = null;
+        for (int i = 0; i < childNodes.getLength(); i++) {
+            if (!(childNodes.item(i) instanceof Element)) {
+                continue;
+            }
+
+            Element child = (Element) childNodes.item(i);
+            if ("aggregation".equals(child.getNodeName()) || 
"aggregation".equals(child.getLocalName())) {
+                AggregationConfig aggregation = new AggregationConfig();
+                assignProperties(aggregation, child, parserContext);
+                
beanDefinition.getPropertyValues().addPropertyValue("aggregation", aggregation);
+            } else if ("prometheus-exporter".equals(child.getNodeName()) || 
"prometheus-exporter".equals(child.getLocalName())) {
+                if (prometheus == null) {
+                    prometheus = new PrometheusConfig();
+                }
+
+                PrometheusConfig.Exporter exporter = new 
PrometheusConfig.Exporter();
+                assignProperties(exporter, child, parserContext);
+                prometheus.setExporter(exporter);
+            } else if ("prometheus-pushgateway".equals(child.getNodeName()) || 
"prometheus-pushgateway".equals(child.getLocalName())) {
+                if (prometheus == null) {
+                    prometheus = new PrometheusConfig();
+                }
+
+                PrometheusConfig.Pushgateway pushgateway = new 
PrometheusConfig.Pushgateway();
+                assignProperties(pushgateway, child, parserContext);
+                prometheus.setPushgateway(pushgateway);
+            }
+        }
+
+        if (prometheus != null) {
+            beanDefinition.getPropertyValues().addPropertyValue("prometheus", 
prometheus);
+        }
+    }
+
+    private static void assignProperties(Object obj, Element ele, 
ParserContext parserContext) {
+        Method[] methods = obj.getClass().getMethods();
+        for (Method method : methods) {
+            if (MethodUtils.isSetter(method)) {
+                String beanProperty = method.getName().substring(3, 
4).toLowerCase() + method.getName().substring(4);
+                String property = StringUtils.camelToSplitName(beanProperty, 
"-");
+                String value = resolveAttribute(ele, property, parserContext);
+                if (StringUtils.isNotEmpty(value)) {
+                    try {
+                        Object v = 
ClassUtils.convertPrimitive(method.getParameterTypes()[0], value);
+                        method.invoke(obj, v);
+                    } catch (IllegalAccessException | 
InvocationTargetException e) {
+                        throw new IllegalStateException(e);
+                    }
+                }
+            }
+        }
+    }
+
     private static void configReferenceBean(Element element, ParserContext 
parserContext, RootBeanDefinition beanDefinition, BeanDefinition 
consumerDefinition) {
         // process interface class
         String interfaceName = resolveAttribute(element, 
ReferenceAttributes.INTERFACE, parserContext);
diff --git 
a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd 
b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
index 45477d1..905fe02 100644
--- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
+++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
@@ -912,14 +912,98 @@
     </xsd:complexType>
 
     <xsd:complexType name="metricsType">
-        <xsd:attribute name="port" type="xsd:string" use="required">
+        <xsd:all>
+                <xsd:element ref="prometheus-exporter" minOccurs="0"/>
+                <xsd:element ref="prometheus-pushgateway" minOccurs="0"/>
+                <xsd:element ref="aggregation" minOccurs="0"/>
+        </xsd:all>
+        <xsd:attribute name="protocol" type="xsd:string">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ The metrics protocol. 
]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+        <xsd:attribute name="port" type="xsd:string">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ Deprecated. No longer use. 
]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+    <xsd:complexType name="prometheusExporterType">
+        <xsd:attribute name="enabled" type="xsd:boolean">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ Enable prometheus exporter. 
]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+        <xsd:attribute name="enable-http-service-discovery" type="xsd:boolean">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ Enable http service discovery for 
prometheus. ]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+        <xsd:attribute name="http-service-discovery-url" type="xsd:string">
             <xsd:annotation>
-                <xsd:documentation><![CDATA[ The metrics service port. 
]]></xsd:documentation>
+                <xsd:documentation><![CDATA[ Http service discovery url. 
]]></xsd:documentation>
             </xsd:annotation>
         </xsd:attribute>
-        <xsd:attribute name="protocol" type="xsd:string" use="required">
+        <xsd:attribute name="metrics-port" type="xsd:integer">
             <xsd:annotation>
-                <xsd:documentation><![CDATA[ The metrics service protocol. 
]]></xsd:documentation>
+                <xsd:documentation><![CDATA[ When using pull method, which 
port to expose. ]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+        <xsd:attribute name="metrics-path" type="xsd:string">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ When using pull mode, which path 
to expose metrics. ]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+    <xsd:complexType name="prometheusPushgatewayType">
+        <xsd:attribute name="enabled" type="xsd:boolean">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ Enable publishing via a 
Prometheus Pushgateway. ]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+        <xsd:attribute name="base-url" type="xsd:string">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ Base URL for the Pushgateway. 
]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+        <xsd:attribute name="username" type="xsd:string">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ Login user of the Prometheus 
Pushgateway. ]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+        <xsd:attribute name="password" type="xsd:string">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ Login password of the Prometheus 
Pushgateway. ]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+        <xsd:attribute name="push-interval" type="xsd:integer">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ Frequency with which to push 
metrics. ]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+        <xsd:attribute name="job" type="xsd:string">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ Job identifier for this 
application instance. ]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+    <xsd:complexType name="aggregationType">
+        <xsd:attribute name="enabled" type="xsd:boolean">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ Enable local aggregation or not. 
]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+        <xsd:attribute name="bucket-num" type="xsd:integer">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ Bucket num for time window 
quantile. ]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+        <xsd:attribute name="time-window-seconds" type="xsd:integer">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ Time window seconds for time 
window quantile. ]]></xsd:documentation>
             </xsd:annotation>
         </xsd:attribute>
     </xsd:complexType>
@@ -1770,4 +1854,21 @@
         </xsd:annotation>
     </xsd:element>
 
+    <xsd:element name="prometheus-exporter" type="prometheusExporterType">
+        <xsd:annotation>
+            <xsd:documentation><![CDATA[ The metrics prometheus exporter 
config. ]]></xsd:documentation>
+        </xsd:annotation>
+    </xsd:element>
+
+    <xsd:element name="prometheus-pushgateway" 
type="prometheusPushgatewayType">
+        <xsd:annotation>
+            <xsd:documentation><![CDATA[ The metrics prometheus pushgateway 
config. ]]></xsd:documentation>
+        </xsd:annotation>
+    </xsd:element>
+
+    <xsd:element name="aggregation" type="aggregationType">
+        <xsd:annotation>
+            <xsd:documentation><![CDATA[ The metrics aggregation config. 
]]></xsd:documentation>
+        </xsd:annotation>
+    </xsd:element>
 </xsd:schema>
diff --git 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java
 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java
index 60cf49c..1d202be 100644
--- 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java
+++ 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java
@@ -45,6 +45,8 @@ import org.springframework.context.annotation.Configuration;
 import java.util.Collection;
 import java.util.List;
 
+import static 
org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;
+
 @SpringBootTest(
         properties = {
                 "dubbo.application.NAME = dubbo-demo-application",
@@ -52,8 +54,15 @@ import java.util.List;
                 "dubbo.registry.address = zookeeper://192.168.99.100:32770",
                 "dubbo.protocol.name=dubbo",
                 "dubbo.protocol.port=20880",
-                "dubbo.metrics.protocol=dubbo",
-                "dubbo.metrics.port=20880",
+                "dubbo.metrics.protocol=prometheus",
+                "dubbo.metrics.prometheus.exporter.enabled=true",
+                
"dubbo.metrics.prometheus.exporter.enable-http-service-discovery=true",
+                
"dubbo.metrics.prometheus.exporter.http-service-discovery-url=localhost:8080",
+                "dubbo.metrics.prometheus.exporter.metrics-port=20888",
+                "dubbo.metrics.prometheus.exporter.metrics-path=/metrics",
+                "dubbo.metrics.aggregation.enabled=true",
+                "dubbo.metrics.aggregation.bucket-num=5",
+                "dubbo.metrics.aggregation.time-window-seconds=120",
                 "dubbo.monitor.address=zookeeper://127.0.0.1:32770",
                 "dubbo.Config-center.address=zookeeper://127.0.0.1:2181",
                 "dubbo.config-Center.group=group1",
@@ -102,8 +111,15 @@ public class SpringBootConfigPropsTest {
         Assertions.assertEquals("zookeeper://127.0.0.1:32770", 
monitorConfig.getAddress());
 
         MetricsConfig metricsConfig = configManager.getMetrics().get();
-        Assertions.assertEquals("dubbo", metricsConfig.getProtocol());
-        Assertions.assertEquals("20880", metricsConfig.getPort());
+        Assertions.assertEquals(PROTOCOL_PROMETHEUS, 
metricsConfig.getProtocol());
+        
Assertions.assertTrue(metricsConfig.getPrometheus().getExporter().getEnabled());
+        
Assertions.assertTrue(metricsConfig.getPrometheus().getExporter().getEnableHttpServiceDiscovery());
+        Assertions.assertEquals("localhost:8080", 
metricsConfig.getPrometheus().getExporter().getHttpServiceDiscoveryUrl());
+        Assertions.assertEquals(20888, 
metricsConfig.getPrometheus().getExporter().getMetricsPort());
+        Assertions.assertEquals("/metrics", 
metricsConfig.getPrometheus().getExporter().getMetricsPath());
+        Assertions.assertEquals(5, 
metricsConfig.getAggregation().getBucketNum());
+        Assertions.assertEquals(120, 
metricsConfig.getAggregation().getTimeWindowSeconds());
+        Assertions.assertTrue(metricsConfig.getAggregation().getEnabled());
 
         List<ProtocolConfig> defaultProtocols = 
configManager.getDefaultProtocols();
         Assertions.assertEquals(1, defaultProtocols.size());
diff --git 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java
 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java
index acc6027..d5eb21b 100644
--- 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java
+++ 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java
@@ -33,6 +33,7 @@ import 
org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
 import org.apache.dubbo.config.spring.registrycenter.RegistryCenter;
 import 
org.apache.dubbo.config.spring.registrycenter.ZookeeperMultipleRegistryCenter;
 import org.apache.dubbo.rpc.model.ModuleModel;
+
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
@@ -45,25 +46,35 @@ import org.springframework.context.annotation.Configuration;
 import java.util.Collection;
 import java.util.List;
 
+import static 
org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;
+
 @SpringBootTest(
-        properties = {
-                "dubbo.applications.application1.name = 
dubbo-demo-application",
-                "dubbo.modules.demo-module.name = dubbo-demo-module",
-                "dubbo.registries.my-registry.address = 
zookeeper://192.168.99.100:32770",
-                "dubbo.protocols.dubbo.port=20880",
-                "dubbo.metricses.my-metrics.protocol=dubbo",
-                "dubbo.metricses.my-metrics.port=20880",
-                
"dubbo.monitors.my-monitor.address=zookeeper://127.0.0.1:32770",
-                
"dubbo.config-centers.my-configcenter.address=zookeeper://127.0.0.1:2181",
-                "dubbo.config-centers.my-configcenter.group=group1",
-                
"dubbo.metadata-reports.my-metadata.address=zookeeper://127.0.0.1:2182",
-                "dubbo.metadata-reports.my-metadata.username=User",
-                "dubbo.providers.my-provider.host=127.0.0.1",
-                "dubbo.consumers.my-consumer.client=netty"
-        },
-        classes = {
-                SpringBootMultipleConfigPropsTest.class
-        }
+    properties = {
+        "dubbo.applications.application1.name = dubbo-demo-application",
+        "dubbo.modules.demo-module.name = dubbo-demo-module",
+        "dubbo.registries.my-registry.address = 
zookeeper://192.168.99.100:32770",
+        "dubbo.protocols.dubbo.port=20880",
+        "dubbo.metricses.my-metrics.protocol=prometheus",
+        "dubbo.metricses.my-metrics.prometheus.pushgateway.enabled=true",
+        
"dubbo.metricses.my-metrics.prometheus.pushgateway.base-url=localhost:9091",
+        "dubbo.metricses.my-metrics.prometheus.pushgateway.username=username",
+        "dubbo.metricses.my-metrics.prometheus.pushgateway.password=password",
+        "dubbo.metricses.my-metrics.prometheus.pushgateway.job=job",
+        "dubbo.metricses.my-metrics.prometheus.pushgateway.push-interval=30",
+        "dubbo.metricses.my-metrics.aggregation.enabled=true",
+        "dubbo.metricses.my-metrics.aggregation.bucket-num=5",
+        "dubbo.metricses.my-metrics.aggregation.time-window-seconds=120",
+        "dubbo.monitors.my-monitor.address=zookeeper://127.0.0.1:32770",
+        
"dubbo.config-centers.my-configcenter.address=zookeeper://127.0.0.1:2181",
+        "dubbo.config-centers.my-configcenter.group=group1",
+        
"dubbo.metadata-reports.my-metadata.address=zookeeper://127.0.0.1:2182",
+        "dubbo.metadata-reports.my-metadata.username=User",
+        "dubbo.providers.my-provider.host=127.0.0.1",
+        "dubbo.consumers.my-consumer.client=netty"
+    },
+    classes = {
+        SpringBootMultipleConfigPropsTest.class
+    }
 )
 @Configuration
 @ComponentScan
@@ -101,8 +112,16 @@ public class SpringBootMultipleConfigPropsTest {
         Assertions.assertEquals("zookeeper://127.0.0.1:32770", 
monitorConfig.getAddress());
 
         MetricsConfig metricsConfig = configManager.getMetrics().get();
-        Assertions.assertEquals("dubbo", metricsConfig.getProtocol());
-        Assertions.assertEquals("20880", metricsConfig.getPort());
+        Assertions.assertEquals(PROTOCOL_PROMETHEUS, 
metricsConfig.getProtocol());
+        
Assertions.assertTrue(metricsConfig.getPrometheus().getPushgateway().getEnabled());
+        Assertions.assertEquals("localhost:9091", 
metricsConfig.getPrometheus().getPushgateway().getBaseUrl());
+        Assertions.assertEquals("username", 
metricsConfig.getPrometheus().getPushgateway().getUsername());
+        Assertions.assertEquals("password", 
metricsConfig.getPrometheus().getPushgateway().getPassword());
+        Assertions.assertEquals("job", 
metricsConfig.getPrometheus().getPushgateway().getJob());
+        Assertions.assertEquals(30, 
metricsConfig.getPrometheus().getPushgateway().getPushInterval());
+        Assertions.assertEquals(5, 
metricsConfig.getAggregation().getBucketNum());
+        Assertions.assertEquals(120, 
metricsConfig.getAggregation().getTimeWindowSeconds());
+        Assertions.assertTrue(metricsConfig.getAggregation().getEnabled());
 
         List<ProtocolConfig> defaultProtocols = 
configManager.getDefaultProtocols();
         Assertions.assertEquals(1, defaultProtocols.size());
diff --git 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandlerTest.java
 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandlerTest.java
index 8bd0991..7415f17 100644
--- 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandlerTest.java
+++ 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandlerTest.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.config.spring.schema;
 
 import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.MetricsConfig;
 import org.apache.dubbo.config.ModuleConfig;
 import org.apache.dubbo.config.MonitorConfig;
 import org.apache.dubbo.config.ProtocolConfig;
@@ -46,6 +47,7 @@ import 
org.springframework.context.support.ClassPathXmlApplicationContext;
 import java.util.Collection;
 import java.util.Map;
 
+import static 
org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.nullValue;
@@ -242,4 +244,60 @@ public class DubboNamespaceHandlerTest {
         String prefix = ((DemoServiceImpl) serviceBean.getRef()).getPrefix();
         assertThat(prefix, is("welcome:"));
     }
+
+    @Test
+    public void testMetricsAggregation() {
+        ClassPathXmlApplicationContext ctx = new 
ClassPathXmlApplicationContext(resourcePath + "/metrics-aggregation.xml");
+        ctx.start();
+
+        ConfigManager configManager = 
ApplicationModel.defaultModel().getApplicationConfigManager();
+
+        MetricsConfig metricsBean = ctx.getBean(MetricsConfig.class);
+        MetricsConfig metrics = configManager.getMetrics().get();
+
+        assertEquals(metrics.getAggregation().getEnabled(), true);
+        assertEquals(metrics.getAggregation().getBucketNum(), 5);
+        assertEquals(metrics.getAggregation().getTimeWindowSeconds(), 120);
+
+        assertEquals(metrics.getAggregation().getEnabled(), 
metricsBean.getAggregation().getEnabled());
+        assertEquals(metrics.getAggregation().getBucketNum(), 
metricsBean.getAggregation().getBucketNum());
+        assertEquals(metrics.getAggregation().getTimeWindowSeconds(), 
metricsBean.getAggregation().getTimeWindowSeconds());
+    }
+
+    @Test
+    public void testMetricsPrometheus() {
+        ClassPathXmlApplicationContext ctx = new 
ClassPathXmlApplicationContext(resourcePath + "/metrics-prometheus.xml");
+        ctx.start();
+
+        ConfigManager configManager = 
ApplicationModel.defaultModel().getApplicationConfigManager();
+
+        MetricsConfig metricsBean = ctx.getBean(MetricsConfig.class);
+        MetricsConfig metrics = configManager.getMetrics().get();
+
+        assertEquals(metrics.getProtocol(), PROTOCOL_PROMETHEUS);
+        assertEquals(metrics.getPrometheus().getExporter().getEnabled(), true);
+        
assertEquals(metrics.getPrometheus().getExporter().getEnableHttpServiceDiscovery(),
 true);
+        
assertEquals(metrics.getPrometheus().getExporter().getHttpServiceDiscoveryUrl(),
 "localhost:8080");
+        assertEquals(metrics.getPrometheus().getExporter().getMetricsPort(), 
20888);
+        assertEquals(metrics.getPrometheus().getExporter().getMetricsPath(), 
"/metrics");
+        assertEquals(metrics.getPrometheus().getPushgateway().getEnabled(), 
true);
+        assertEquals(metrics.getPrometheus().getPushgateway().getBaseUrl(), 
"localhost:9091");
+        
assertEquals(metrics.getPrometheus().getPushgateway().getPushInterval(), 30);
+        assertEquals(metrics.getPrometheus().getPushgateway().getUsername(), 
"username");
+        assertEquals(metrics.getPrometheus().getPushgateway().getPassword(), 
"password");
+        assertEquals(metrics.getPrometheus().getPushgateway().getJob(), "job");
+
+        assertEquals(metricsBean.getProtocol(), PROTOCOL_PROMETHEUS);
+        assertEquals(metricsBean.getPrometheus().getExporter().getEnabled(), 
true);
+        
assertEquals(metricsBean.getPrometheus().getExporter().getEnableHttpServiceDiscovery(),
 true);
+        
assertEquals(metricsBean.getPrometheus().getExporter().getHttpServiceDiscoveryUrl(),
 "localhost:8080");
+        
assertEquals(metricsBean.getPrometheus().getExporter().getMetricsPort(), 20888);
+        
assertEquals(metricsBean.getPrometheus().getExporter().getMetricsPath(), 
"/metrics");
+        
assertEquals(metricsBean.getPrometheus().getPushgateway().getEnabled(), true);
+        
assertEquals(metricsBean.getPrometheus().getPushgateway().getBaseUrl(), 
"localhost:9091");
+        
assertEquals(metricsBean.getPrometheus().getPushgateway().getPushInterval(), 
30);
+        
assertEquals(metricsBean.getPrometheus().getPushgateway().getUsername(), 
"username");
+        
assertEquals(metricsBean.getPrometheus().getPushgateway().getPassword(), 
"password");
+        assertEquals(metricsBean.getPrometheus().getPushgateway().getJob(), 
"job");
+    }
 }
diff --git 
a/dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/metrics-aggregation.xml
 
b/dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/metrics-aggregation.xml
new file mode 100644
index 0000000..d0eafd7
--- /dev/null
+++ 
b/dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/metrics-aggregation.xml
@@ -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.
+  -->
+<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo";
+       xmlns="http://www.springframework.org/schema/beans";
+       xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
+    http://dubbo.apache.org/schema/dubbo 
http://dubbo.apache.org/schema/dubbo/dubbo.xsd
+    ">
+
+    <!-- current application configuration -->
+    <dubbo:application name="demo-consumer" />
+
+    <dubbo:metrics>
+        <dubbo:aggregation enabled="true" bucket-num="5" 
time-window-seconds="120" />
+    </dubbo:metrics>
+
+</beans>
diff --git 
a/dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/metrics-prometheus.xml
 
b/dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/metrics-prometheus.xml
new file mode 100644
index 0000000..b90e844
--- /dev/null
+++ 
b/dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/metrics-prometheus.xml
@@ -0,0 +1,32 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo";
+       xmlns="http://www.springframework.org/schema/beans";
+       xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
+    http://dubbo.apache.org/schema/dubbo 
http://dubbo.apache.org/schema/dubbo/dubbo.xsd
+    ">
+
+    <!-- current application configuration -->
+    <dubbo:application name="demo-consumer" />
+
+    <dubbo:metrics protocol="prometheus">
+        <dubbo:prometheus-exporter enabled="true" 
enable-http-service-discovery="true" 
http-service-discovery-url="localhost:8080" metrics-port="20888" 
metrics-path="/metrics" />
+        <dubbo:prometheus-pushgateway enabled="true" base-url="localhost:9091" 
push-interval="30" username="username" password="password" job="job" />
+    </dubbo:metrics>
+
+</beans>
diff --git a/dubbo-metrics/dubbo-metrics-api/pom.xml 
b/dubbo-metrics/dubbo-metrics-api/pom.xml
new file mode 100644
index 0000000..cb6e664
--- /dev/null
+++ b/dubbo-metrics/dubbo-metrics-api/pom.xml
@@ -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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.dubbo</groupId>
+        <artifactId>dubbo-metrics</artifactId>
+        <version>${revision}</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>dubbo-metrics-api</artifactId>
+    <packaging>jar</packaging>
+    <name>${project.artifactId}</name>
+    <description>The metrics module of dubbo project</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>
diff --git a/dubbo-metrics/dubbo-metrics-prometheus/pom.xml 
b/dubbo-metrics/dubbo-metrics-prometheus/pom.xml
new file mode 100644
index 0000000..0020915
--- /dev/null
+++ b/dubbo-metrics/dubbo-metrics-prometheus/pom.xml
@@ -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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.dubbo</groupId>
+        <artifactId>dubbo-metrics</artifactId>
+        <version>${revision}</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>dubbo-metrics-prometheus</artifactId>
+    <packaging>jar</packaging>
+    <name>${project.artifactId}</name>
+    <description>The prometheus metrics module of dubbo project</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>
diff --git a/dubbo-metrics/pom.xml b/dubbo-metrics/pom.xml
new file mode 100644
index 0000000..1f0d32a
--- /dev/null
+++ b/dubbo-metrics/pom.xml
@@ -0,0 +1,36 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <modules>
+        <module>dubbo-metrics-api</module>
+        <module>dubbo-metrics-prometheus</module>
+    </modules>
+    <parent>
+        <groupId>org.apache.dubbo</groupId>
+        <artifactId>dubbo-parent</artifactId>
+        <version>${revision}</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>dubbo-metrics</artifactId>
+    <packaging>pom</packaging>
+    <name>${project.artifactId}</name>
+    <description>The metrics module of dubbo project</description>
+    <properties>
+        <skip_maven_deploy>false</skip_maven_deploy>
+    </properties>
+</project>
diff --git 
a/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/MetricsService.java
 
b/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/MetricsService.java
index 41c7b3b..6670c85 100644
--- 
a/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/MetricsService.java
+++ 
b/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/MetricsService.java
@@ -17,6 +17,11 @@
 
 package org.apache.dubbo.monitor;
 
+/**
+ * @deprecated After metrics config is refactored.
+ * This class should no longer use and will be deleted in the future.
+ */
+@Deprecated
 public interface MetricsService {
     String getMetricsByGroup(String group);
 }
diff --git 
a/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/support/MetricsServiceDetector.java
 
b/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/support/MetricsServiceDetector.java
index 3b9fa15..0eb6406 100644
--- 
a/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/support/MetricsServiceDetector.java
+++ 
b/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/monitor/support/MetricsServiceDetector.java
@@ -19,6 +19,11 @@ package org.apache.dubbo.monitor.support;
 import org.apache.dubbo.monitor.MetricsService;
 import org.apache.dubbo.rpc.model.BuiltinServiceDetector;
 
+/**
+ * @deprecated After metrics config is refactored.
+ * This class should no longer use and will be deleted in the future.
+ */
+@Deprecated
 public class MetricsServiceDetector implements BuiltinServiceDetector {
 
     @Override
diff --git 
a/dubbo-monitor/dubbo-monitor-default/src/main/java/org/apache/dubbo/monitor/dubbo/MetricsFilter.java
 
b/dubbo-monitor/dubbo-monitor-default/src/main/java/org/apache/dubbo/monitor/dubbo/MetricsFilter.java
index c2cce61..73fd5ef 100644
--- 
a/dubbo-monitor/dubbo-monitor-default/src/main/java/org/apache/dubbo/monitor/dubbo/MetricsFilter.java
+++ 
b/dubbo-monitor/dubbo-monitor-default/src/main/java/org/apache/dubbo/monitor/dubbo/MetricsFilter.java
@@ -59,8 +59,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import static 
org.apache.dubbo.common.constants.CommonConstants.DEFAULT_PROTOCOL;
 import static 
org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_SERVICE_COMPONENT_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.METRICS_PORT;
-import static 
org.apache.dubbo.common.constants.CommonConstants.METRICS_PROTOCOL;
 import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
 import static org.apache.dubbo.monitor.Constants.DUBBO_CONSUMER;
 import static org.apache.dubbo.monitor.Constants.DUBBO_CONSUMER_METHOD;
@@ -70,6 +68,11 @@ import static 
org.apache.dubbo.monitor.Constants.DUBBO_PROVIDER_METHOD;
 import static org.apache.dubbo.monitor.Constants.METHOD;
 import static org.apache.dubbo.monitor.Constants.SERVICE;
 
+/**
+ * @deprecated After metrics config is refactored.
+ * This filter should no longer use and will be deleted in the future.
+ */
+@Deprecated
 public class MetricsFilter implements Filter, ExtensionAccessorAware, 
ScopeModelAware {
 
     private static final Logger logger = 
LoggerFactory.getLogger(MetricsFilter.class);
@@ -79,6 +82,9 @@ public class MetricsFilter implements Filter, 
ExtensionAccessorAware, ScopeModel
     private ExtensionAccessor extensionAccessor;
     private ApplicationModel applicationModel;
 
+    private static final String METRICS_PORT = "metrics.port";
+    private static final String METRICS_PROTOCOL = "metrics.protocol";
+
     @Override
     public void setApplicationModel(ApplicationModel applicationModel) {
         this.applicationModel = applicationModel;
diff --git 
a/dubbo-monitor/dubbo-monitor-default/src/test/java/org/apache/dubbo/monitor/dubbo/MetricsFilterTest.java
 
b/dubbo-monitor/dubbo-monitor-default/src/test/java/org/apache/dubbo/monitor/dubbo/MetricsFilterTest.java
index 8517547..464f2fb 100644
--- 
a/dubbo-monitor/dubbo-monitor-default/src/test/java/org/apache/dubbo/monitor/dubbo/MetricsFilterTest.java
+++ 
b/dubbo-monitor/dubbo-monitor-default/src/test/java/org/apache/dubbo/monitor/dubbo/MetricsFilterTest.java
@@ -16,14 +16,6 @@
  */
 package org.apache.dubbo.monitor.dubbo;
 
-import com.alibaba.metrics.FastCompass;
-import com.alibaba.metrics.IMetricManager;
-import com.alibaba.metrics.MetricLevel;
-import com.alibaba.metrics.MetricManager;
-import com.alibaba.metrics.MetricName;
-import com.alibaba.metrics.common.MetricObject;
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.utils.NetUtils;
 import org.apache.dubbo.monitor.MetricsService;
@@ -37,6 +29,15 @@ import org.apache.dubbo.rpc.RpcException;
 import org.apache.dubbo.rpc.RpcInvocation;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;
+
+import com.alibaba.metrics.FastCompass;
+import com.alibaba.metrics.IMetricManager;
+import com.alibaba.metrics.MetricLevel;
+import com.alibaba.metrics.MetricManager;
+import com.alibaba.metrics.MetricName;
+import com.alibaba.metrics.common.MetricObject;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
@@ -50,7 +51,6 @@ import java.util.concurrent.Callable;
 import java.util.function.Function;
 
 import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
-import static org.apache.dubbo.common.constants.CommonConstants.METRICS_PORT;
 import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
 import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
@@ -81,7 +81,7 @@ public class MetricsFilterTest {
 
     private URL getUrl() {
         return URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":" + port +
-                "/org.apache.dubbo.monitor.dubbo.service.DemoService?" + 
METRICS_PORT + "=" + port);
+                "/org.apache.dubbo.monitor.dubbo.service.DemoService?" + 
"metrics.port" + "=" + port);
     }
 
     private void onInvokeReturns(Invoker<DemoService> invoker, AppResponse 
response) {
diff --git 
a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboConfigurationProperties.java
 
b/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboConfigurationProperties.java
index af8a429..165a90c 100644
--- 
a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboConfigurationProperties.java
+++ 
b/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboConfigurationProperties.java
@@ -20,6 +20,7 @@ import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.ConfigKeys;
 import org.apache.dubbo.config.ConsumerConfig;
 import org.apache.dubbo.config.MetadataReportConfig;
+import org.apache.dubbo.config.MetricsConfig;
 import org.apache.dubbo.config.ModuleConfig;
 import org.apache.dubbo.config.MonitorConfig;
 import org.apache.dubbo.config.ProtocolConfig;
@@ -84,6 +85,9 @@ public class DubboConfigurationProperties {
     @NestedConfigurationProperty
     private MetadataReportConfig metadataReport = new MetadataReportConfig();
 
+    @NestedConfigurationProperty
+    private MetricsConfig metrics = new MetricsConfig();
+
     // Multiple Config Bindings
 
     private Map<String, ModuleConfig> modules = new LinkedHashMap<>();
@@ -102,6 +106,8 @@ public class DubboConfigurationProperties {
 
     private Map<String, MetadataReportConfig> metadataReports = new 
LinkedHashMap<>();
 
+    private Map<String, MetricsConfig> metricses = new LinkedHashMap<>();
+
     public Config getConfig() {
         return config;
     }
@@ -190,6 +196,14 @@ public class DubboConfigurationProperties {
         this.metadataReport = metadataReport;
     }
 
+    public MetricsConfig getMetrics() {
+        return metrics;
+    }
+
+    public void setMetrics(MetricsConfig metrics) {
+        this.metrics = metrics;
+    }
+
     public Map<String, ModuleConfig> getModules() {
         return modules;
     }
@@ -254,6 +268,14 @@ public class DubboConfigurationProperties {
         this.metadataReports = metadataReports;
     }
 
+    public Map<String, MetricsConfig> getMetricses() {
+        return metricses;
+    }
+
+    public void setMetricses(Map<String, MetricsConfig> metricses) {
+        this.metricses = metricses;
+    }
+
     static class Config {
 
         /**
diff --git a/pom.xml b/pom.xml
index 234cf9d..c243a3e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -150,6 +150,7 @@
         <module>dubbo-configcenter</module>
         <module>dubbo-dependencies</module>
         <module>dubbo-metadata</module>
+        <module>dubbo-metrics</module>
         <module>dubbo-build-tools</module>
         <module>dubbo-spring-boot</module>
         <module>dubbo-native</module>

Reply via email to