- [x] I have searched the [issues](https://github.com/apache/dubbo/issues) of this repository and believe that this is not a duplicate.
- [ ] I have checked the [FAQ](https://github.com/apache/dubbo/blob/master/FAQ.md) of this repository and believe that this is not a duplicate.

All problem already resolve by Dubbo SPI on my framework, but I think I should share those problems and the reason why those problems come up. 

Please Dubbo team fix those issue for good.



### Environment

* Dubbo version: Dubbo 2.7.5
* Operating System version: MacOS
* Java version: Oracle JDK 8

Finally I back to the Vertion 2.7.4.1, And This is all issue of the Dubbo 2.7.5 I found:

- **Failure due to the Dubbo starting early**. This is my environment:

  - Dubbo 2.7.5 + Nacos 1.1.4
  - Use Dynamic Config Center
  - Spring boot 2.1.9
  - Use YAML Config

  In this case, the Dubbo will be startup before the  `ConfigCenterConfig` inject into `DubboBootstrap`, it make Dubbo use default config and starting failure. And the reason of the Dubbo startup is **Spring framework scan Dubbo Service Interface and initial it, and the Dubbo Service Interface active the Dubbo framework**. the Dubbo framework not even get the `ConfigCenterConfig` at that time.

  

  After reading the Dubbo source code, I found some key code in the class `DubboBootstrap`, method name `startConfigCenter`, line 560.

  ```java
  // Get the class "ConfigCenterConfig"
  Collection<ConfigCenterConfig> configCenters = configManager.getConfigCenters();
  
  if (CollectionUtils.isNotEmpty(configCenters)) {
    CompositeDynamicConfiguration compositeDynamicConfiguration = new CompositeDynamicConfiguration();
    for (ConfigCenterConfig configCenter : configCenters) {
      configCenter.refresh();
      ConfigValidationUtils.validateConfigCenterConfig(configCenter);
    
      // The method "prepareEnvironment" get all dubbo config from remote server
      compositeDynamicConfiguration.addConfiguration(prepareEnvironment(configCenter));
    }
    environment.setDynamicConfiguration(compositeDynamicConfiguration);
  }
  configManager.refreshAll();
  ```

  

  And this is the code I use to fix that problem( This code can not fix the problem in some case because it still depend on the order of the Bean initialize in Spring framework, that is the reason why I specified name at `@Configuration`. for the `@DependOn`  ):

  ```java
  @Order(-1)
  @AllArgsConstructor
  @Configuration("apacheDubboBootstrap")
  @ConditionalOnClass(name = "org.apache.dubbo.config.ConfigCenterConfig")
  public static class ApacheDubboBootstrap {
  
    private final DynamicConfigProperties properties;
      
    @PostConstruct
    public void init() {
      // 在 Spring boot 环境下由于 Dubbo 接口的代理类创建间接触发了 Dubbo 框架流程
      // 这一行代码是为了解决启动优先级的问题, 在触发 Dubbo 框架流程之前注入动态配置中心配置
      // 而依赖 Spring boot 进行注入有可能会因为 Dubbo 先启动而不知道存在配置中心导致启动失败
      DubboBootstrap.getInstance().configCenter(properties.ofConfigCenterConfig());
    }
  }
  ```



- **Not friendly with the YAML config**

  For the history reason, the Dubbo framework use XML as config foramt at early, then Properties come up. And now I found that the Dubbo not identify and not inject the YAML config, only XML and Properties can.

  

  ###### For example, This is the qos server config in YAML:

  ```yaml
  # Wrong config
  # This config ( just qos-enable ) problem seem like fixed in Dubbo 2.7.5 ? But I haven't verified yet
  dubbo:
    application:
      qos-enable: true
      
  # Correct config
  dubbo:
    application:
      qos.enable: true
  ```

  If you run Dubbo as debug mode and put some breakpoint in the class `ApplicationConfig`, you can see the method `setQosEnable` only be called when you write `qos.enable` . And what about `qos-enable` ? Just nothing happen.

  

  ###### And other example, The `ConfigCenterConfig`:

  ```yaml
  dubbo:
    config-center:
      address: nacos://xxxx
      config-file: xxxxxx
      group: xxxxxx
      namespace: xxxxxx
  ```

  Only `address` is effective in those configs( The method `setAddress` has been called ) and other config still keep that default value( Nothing happen on the setter of those property ). So that I have to write my configuration and use it config Dubbo:

  

  ```java
  public class DynamicConfigProperties {
    public static final String PREFIX = "dubbo.config-server";
  
      /**
       * Nacos 服务 Ip 地址
       */
      private String serverAddr;
    
    // some property...
    
    public org.apache.dubbo.config.ConfigCenterConfig ofConfigCenterConfig() {
      org.apache.dubbo.config.ConfigCenterConfig config = new ConfigCenterConfig();
  
      Map<String, String> parameters = new HashMap<>(4);
  
      setParameter(parameters, PropertyKeyConst.ACCESS_KEY, accessKey);
      setParameter(parameters, PropertyKeyConst.SECRET_KEY, secretKey);
      setParameter(parameters, PropertyKeyConst.ENDPOINT, endpoint);
  
      config.setParameters(parameters);
  
      config.setHighestPriority(allowOverride);
      config.setNamespace(namespace);
      config.setAddress(serverAddr);
      config.setConfigFile(dataId);
      config.setCheck(abortOnFail);
      config.setTimeout(timeout);
      config.setGroup(group);
  
      return config;
    }
  }
  ```

  

  ###### The last example, let see the `DubboBootstrap`, method `prepareEnvironment`, line 828 & 829.

  ```java
  DynamicConfiguration dynamicConfiguration = getDynamicConfiguration(configCenter.toUrl());
  
  // Get config from remote server.
  String configContent = dynamicConfiguration.getProperties(configCenter.getConfigFile(), configCenter.getGroup());
  
  String appGroup = getApplication().getName();
  String appConfigContent = null;
  if (isNotEmpty(appGroup)) {
      appConfigContent = dynamicConfiguration.getProperties
              (isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile(),
                      appGroup
              );
  }
  try {
      environment.setConfigCenterFirst(configCenter.isHighestPriority());
    
      // It force all remote config must use "properties" format.
      environment.updateExternalConfigurationMap(parseProperties(configContent));
      environment.updateAppExternalConfigurationMap(parseProperties(appConfigContent));
    
    
  } catch (IOException e) {
      throw new IllegalStateException("Failed to parse configurations from Config Center.", e);
  }
  ```

  Because the method `parseProperties`, I have to create my own protocol `banacos` and `BanacosDynamicConfiguration`, the goal is parse yaml and tranform to properties format.

  

  It should be add a property name `format`( or `file-extension` like nacos client ? ) to decide what parser should be Dubbo use, rather than write those dead code.

  

- **Metadata server not effective, and the `ServiceNameMapping` write meta data anywhere**

  The reason of meta server not effective is same with my first issue "**Failure due to the Dubbo starting early**". Let see `DubboBootstrap` again, the method `startMetadataReport`:

  ```java
  ApplicationConfig applicationConfig = getApplication();
  
  String metadataType = applicationConfig.getMetadataType();
  // FIXME, multiple metadata config support.
  Collection<MetadataReportConfig> metadataReportConfigs = configManager.getMetadataConfigs();
  if (CollectionUtils.isEmpty(metadataReportConfigs)) {
    if (REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) {
      throw new IllegalStateException("No MetadataConfig found, you must specify the remote Metadata Center address when 'metadata=remote' is enabled.");
    }
    return;
  }
  MetadataReportConfig metadataReportConfig = metadataReportConfigs.iterator().next();
  ConfigValidationUtils.validateMetadataConfig(metadataReportConfig);
  if (!metadataReportConfig.isValid()) {
    return;
  }
  
  MetadataReportInstance.init(metadataReportConfig.toUrl());
  ```

  

  Is it familiar ? Dubbo activate too soon, even before any config injected, that is the reason why some functions is not work on Dubbo 2.7.5 . We should pay attention to the Bean initialize, especially startup Dubbo under Spring framrwork.

  

  And this is the last issue for this article, the class `DynamicConfigurationServiceNameMapping` push metadata to anywhere:

  ```java
  @Override
  public void map(String serviceInterface, String group, String version, String protocol) {
  
    if (IGNORED_SERVICE_INTERFACES.contains(serviceInterface)) {
      return;
    }
  
    // The value of variable 'dynamicConfiguration' is CompositeDynamicConfiguration
    DynamicConfiguration dynamicConfiguration = DynamicConfiguration.getDynamicConfiguration();
  }
  ```

  The javadoc of the class `CompositeDynamicConfiguration`  is ***support multiple config center, simply iterating each concrete config center***. It mean this class will push metadata to any config center we configed.

  

  In my opinion, those "metadata" should push to metadata server rather than config server. Now every I startup Dubbo service as provider, my config server always fill all data that useless in my view. Just a mess on my config server If I startup all Dubbo service.
/**
     * Add an instance of {@link EventListener}
     *
     * @param listener {@link EventListener}
     * @return {@link DubboBootstrap}
     */
    public DubboBootstrap addEventListener(EventListener<?> listener) {
        eventDispatcher.addEventListener(listener);
        return this;
    }
    /**
     * export {@link MetadataService}
     */
    private void exportMetadataService() {
        metadataServiceExporter.export();
    }
    private void unexportMetadataService() {
        if (metadataServiceExporter != null && metadataServiceExporter.isExported()) {
            metadataServiceExporter.unexport();
        }
    }
    private void exportServices() {
        configManager.getServices().forEach(sc -> {
            
            ServiceConfig serviceConfig = (ServiceConfig) sc;
            serviceConfig.setBootstrap(this);
            if (exportAsync) {
                ExecutorService executor = executorRepository.getServiceExporterExecutor();
                Future<?> future = executor.submit(() -> {
                    sc.export();