ServiceComb【2】CSE配置加载机制

236 阅读22分钟

CSE的配置管理和加载功能在foundation-config模块中实现,完成配置项的加载和处理。

配置文件的加载

foundations\foundation-config\src\main\resources\META-INF\spring\cse.bean.xml文件实现了配置的初始化,文件的内容如下:

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean class="org.apache.servicecomb.config.ConfigurationSpringInitializer"/>
  <bean class="org.apache.servicecomb.config.DynamicPropertiesImpl"/>
</beans>

此处存在两个初始化入口类,ConfigurationSpringInitializer和DynamicPropertiesImpl。

ConfigurationSpringInitializer

实现配置的加载功能,将动态配置和microservice.yaml加载到spring,properties/.yml加载到archivs.

/**
 *  Adapt spring PropertySource and Archaius Configuration
 *  spring     vs      archaius
 *        (add)     |      dynamic(configcenter)
 *  system property           |      system property
 *  environment               |      environment
 *  *properties/*.yml        |       (add)
 *       (add)                |      microservice.yaml
 *
 *  add dynamic configuration, microserive.yaml to spring, add *properties/*.yml to archaius
 *
 *  NOTICE: we are not duplicate spring system property and environment property source, this will cause some problem
 *  related to precedence of a KEY-VAlUE. That is cse.test in dynamic config may not override servicecomb.test in yml.
 *  Users need to use the same key as what is in config file to override.
 */
// PropertyPlaceholderConfigurer类是将占位符指向的数据库配置信息放在bean中定义的工具
// EnvironmentAware为spring的接口:凡注册到Spring容器内的bean,实现了EnvironmentAware接口重写setEnvironment方法后,在工程启动时可以获得application.properties的配置文件配置的属性值。
public class ConfigurationSpringInitializer extends PropertyPlaceholderConfigurer implements EnvironmentAware {
  private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationSpringInitializer.class);

  public static final String EXTRA_CONFIG_SOURCE_PREFIX = "extraConfig-";

  public ConfigurationSpringInitializer() {
    setOrder(Ordered.LOWEST_PRECEDENCE / 2);
	// 无法解析的占位符不报错
    setIgnoreUnresolvablePlaceholders(true);
  }

  /**
   * Get configurations from Spring, merge them into the configurations of ServiceComb.
   * @param environment From which to get the extra config.
   */
  // 重新EnvironmentAware的方法,获取当前的系统配置
  @Override
  public void setEnvironment(Environment environment) {
    // 当前Environment的实现类为StandardEnvironment
    String environmentName = generateNameForEnvironment(environment);
    LOGGER.info("Environment received, will get configurations from [{}].", environmentName);

    Map<String, Object> extraConfig = getAllProperties(environment);
    // 此处掉ConfigUtil的静态方法功能
	// 对应的key为extraConfig-org.springframework.core.env.StandardEnvironment@1296928719
    ConfigUtil.addExtraConfig(EXTRA_CONFIG_SOURCE_PREFIX + environmentName, extraConfig);

	// 加载业务配置
    ConfigUtil.installDynamicConfig();
    // 将当前的配置信息加载到spring中
    setUpSpringPropertySource(environment);
  }

  private void setUpSpringPropertySource(Environment environment) {
    // 当前的StanardEnvironment是ConfigurableEnvironment的子类
    if (environment instanceof ConfigurableEnvironment) {
      ConfigurableEnvironment ce = (ConfigurableEnvironment) environment;
	  // 业务配置加载扩展点
      ConfigCenterConfigurationSource configCenterConfigurationSource =
          SPIServiceUtils.getTargetService(ConfigCenterConfigurationSource.class);
      if (configCenterConfigurationSource != null) {
        try {
          ce.getPropertySources()
              .addFirst(new MapPropertySource("dynamic-source", configCenterConfigurationSource.getCurrentData()));
        } catch (Exception e) {
          LOGGER.warn("set up spring property source failed. msg: {}", e.getMessage());
        }
      }
      ConcurrentCompositeConfiguration concurrentCompositeConfiguration = ConfigUtil.createLocalConfig();
      ce.getPropertySources().addLast(
          new EnumerablePropertySource<ConcurrentCompositeConfiguration>("microservice.yaml",
              concurrentCompositeConfiguration) {
            private String[] propertyNames = null;

            @Override
            public String[] getPropertyNames() {
              if (propertyNames == null) {
                List<String> keyList = Lists.newArrayList(this.source.getKeys());
                propertyNames = keyList.toArray(new String[keyList.size()]);
              }
              return propertyNames;
            }

            @Override
            public Object getProperty(String s) {
              return this.source.getProperty(s);
            }
          });
    }
  }

  @Override
  protected Properties mergeProperties() throws IOException {
    Properties properties = super.mergeProperties();

    AbstractConfiguration config = ConfigurationManager.getConfigInstance();
    Iterator<String> iter = config.getKeys();
    while (iter.hasNext()) {
      String key = iter.next();
      Object value = config.getProperty(key);
      properties.put(key, value);
    }
    return properties;
  }

  @Override
  protected String resolvePlaceholder(String placeholder, Properties props) {
    String propertyValue = super.resolvePlaceholder(placeholder, props);
    if (propertyValue == null) {
      return DynamicPropertyFactory.getInstance().getStringProperty(placeholder, null).get();
    }
    return propertyValue;
  }

  /**
   * Try to get a name for identifying the environment.
   * @param environment the target that the name is generated for.
   * @return The generated name for the environment.
   */
  private String generateNameForEnvironment(Environment environment) {
    String environmentName = environment.getProperty("spring.config.name");
    if (!StringUtils.isEmpty(environmentName)) {
      return environmentName;
    }

    environmentName = environment.getProperty("spring.application.name");
    if (!StringUtils.isEmpty(environmentName)) {
      return environmentName;
    }
    // 在CSE的框架中,如上的值一般不会配置,因此走到此处 
	// 例如某次的返回值如下: org.springframework.core.env.StandardEnvironment@985487390
    return environment.getClass().getName() + "@" + environment.hashCode();
  }

  /**
   * Traversal all {@link PropertySource} of {@link ConfigurableEnvironment}, and try to get all properties.
   */
  // 从Environment中解析属性
  private Map<String, Object> getAllProperties(Environment environment) {
    Map<String, Object> configFromSpringBoot = new HashMap<>();

	// StandardEnvironment是ConfigurableEnvironment的子类
    if (!(environment instanceof ConfigurableEnvironment)) {
      return configFromSpringBoot;
    }

    ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment;
	// configurableEnvironment.getPropertySources()中当前包含两个实现
	// MapPropertySource和SystemEnvironmentPropertySource
    for (PropertySource<?> propertySource : configurableEnvironment.getPropertySources()) {
      getProperties(configurableEnvironment, propertySource, configFromSpringBoot);
    }
    return configFromSpringBoot;
  }

  /**
   * Get property names from {@link EnumerablePropertySource}, and get property value from {@link ConfigurableEnvironment#getProperty(String)}
   */
  private void getProperties(ConfigurableEnvironment environment, PropertySource<?> propertySource,
      Map<String, Object> configFromSpringBoot) {
    if (propertySource instanceof CompositePropertySource) {
      // recursively get EnumerablePropertySource
      CompositePropertySource compositePropertySource = (CompositePropertySource) propertySource;
      compositePropertySource.getPropertySources().forEach(ps -> getProperties(environment, ps, configFromSpringBoot));
      return;
    }
	// 对于MapPropertySource,是EnumerablePropertySource的实现类
	// 对于SystemEnvironmentPropertySource,是EnumerablePropertySource的实现类
    if (propertySource instanceof EnumerablePropertySource) {
      EnumerablePropertySource<?> enumerablePropertySource = (EnumerablePropertySource<?>) propertySource;
	  // 以本地启动的CSE服务为例,enumerablePropertySource.getPropertyNames()中包含的配置项名称为:["java.runtime.name","scb-scan-package","sun.boot.library.path","java.vm.version","java.vm.vendor","java.vendor.url","path.separator","java.vm.name","file.encoding.pkg","user.country","user.script","sun.java.launcher","sun.os.patch.level","java.vm.specification.name","user.dir","intellij.debug.agent","java.runtime.version","java.awt.graphicsenv","java.endorsed.dirs","os.arch","java.io.tmpdir","line.separator","java.vm.specification.vendor","user.variant","os.name","sun.jnu.encoding","java.library.path","jboss.modules.system.pkgs","java.specification.name","java.class.version","sun.management.compiler","os.version","user.home","user.timezone","java.awt.printerjob","file.encoding","java.specification.version","java.class.path","user.name","java.vm.specification.version","sun.java.command","java.home","sun.arch.data.model","user.language","java.specification.vendor","org.apache.logging.log4j.assignedSequences","awt.toolkit","java.vm.info","java.version","java.ext.dirs","sun.boot.class.path","java.vendor","file.separator","java.vendor.url.bug","sun.io.unicode.encoding","sun.cpu.endian","sun.desktop","sun.cpu.isalist"]
	  // 以本地启动的CSE服务为例,SystemEnvironmentPropertySource中包含的配置项名称为:["configsetroot","USERDOMAIN_ROAMINGPROFILE","GIT_HOME","PROCESSOR_LEVEL","SESSIONNAME","ALLUSERSPROFILE","PROCESSOR_ARCHITECTURE","PSModulePath","SystemDrive","JRE_HOME","SCOOP","MOZ_PLUGIN_PATH","USERNAME","USERDNSDOMAIN","MOSQUITTO_DIR","ProgramFiles(x86)","FPS_BROWSER_USER_PROFILE_STRING","PYTHONPATH","PATHEXT","DriverData","PcAccess","ProgramData","ProgramW6432","HOMEPATH","PROCESSOR_IDENTIFIER","HADOOP_HOME","M2_HOME","ProgramFiles","PUBLIC","windir","=::","LOCALAPPDATA","ChocolateyLastPathUpdate","IntelliJ IDEA","USERDOMAIN","FPS_BROWSER_APP_PROFILE_STRING","LOGONSERVER","JAVA_HOME","GRADLE_HOME","PYSPARK_PYTHON","OneDrive","APPDATA","GRADLE_USER_HOME","SPARK_HOME","ChocolateyInstall","CommonProgramFiles","Path","PyCharm","OS","COMPUTERNAME","PROCESSOR_REVISION","RSKUSERNAME","CLASSPATH","CommonProgramW6432","ComSpec","RADONFILESENCODING","SystemRoot","TEMP","HOMEDRIVE","USERPROFILE","TMP","CommonProgramFiles(x86)","NUMBER_OF_PROCESSORS","IDEA_INITIAL_DIRECTORY"],对应的均为操作系统变量的配置
      for (String propertyName : enumerablePropertySource.getPropertyNames()) {
        try {
		  // configFromSpringBoot中存储了从Environment中获取的配置值
          configFromSpringBoot.put(propertyName, environment.getProperty(propertyName, Object.class));
        } catch (Exception e) {
          if (ignoreResolveFailure()) {
            LOGGER.warn("set up spring property source failed.", e);
          } else {
            throw new RuntimeException("set up spring property source failed.If you still want to start up the application and ignore errors, you can set servicecomb.config.ignoreResolveFailure to true.", e);
          }
        }
      }
      return;
    }

    LOGGER.debug("a none EnumerablePropertySource is ignored, propertySourceName = [{}]", propertySource.getName());
  }

  private boolean ignoreResolveFailure() {
    return ConfigUtil
            .createLocalConfig()
            .getBoolean("servicecomb.config.ignoreResolveFailure", false);
  }
}

org.apache.servicecomb.config.ConfigUtil实现了配置管理工具类的功能,实现逻辑如下:

public final class ConfigUtil {
  private static final Logger LOGGER = LoggerFactory.getLogger(ConfigUtil.class);

  private static final String MICROSERVICE_CONFIG_LOADER_KEY = "cse-microservice-config-loader";

  private static Map<String, Object> localConfig = new HashMap<>();

  /**
   * <p>The configurations not read by ServiceComb.</p>
   * <p>
   * For example, this map can store the configurations read by SpringBoot from application.properties,
   * If users write the configurations of ServiceComb into application.yml instead of microservice.yaml,
   * this can help {@link ConfigUtil} load config correctly.
   * </p>
   */
  private static final Map<String, Map<String, Object>> EXTRA_CONFIG_MAP = new LinkedHashMap<>();

  private ConfigUtil() {
  }

  public static void setConfigs(Map<String, Object> config) {
    localConfig = config;
  }

  public static void addConfig(String key, Object value) {
    localConfig.put(key, value);
  }

  public static Object getProperty(String key) {
    Object config = DynamicPropertyFactory.getBackingConfigurationSource();
    return getProperty(config, key);
  }

  public static Object getProperty(Object config, String key) {
    if (null != config && Configuration.class.isInstance(config)) {
      Configuration configuration = (Configuration) config;
      return configuration.getProperty(key);
    }
    return null;
  }

  private static void setMicroserviceConfigLoader(Configuration config, MicroserviceConfigLoader loader) {
    config.setProperty(MICROSERVICE_CONFIG_LOADER_KEY, loader);
  }

  public static MicroserviceConfigLoader getMicroserviceConfigLoader() {
    return (MicroserviceConfigLoader) getProperty(MICROSERVICE_CONFIG_LOADER_KEY);
  }

  public static MicroserviceConfigLoader getMicroserviceConfigLoader(Configuration config) {
    return (MicroserviceConfigLoader) getProperty(config, MICROSERVICE_CONFIG_LOADER_KEY);
  }

  // 创建本地配置管理对象
  public static ConcurrentCompositeConfiguration createLocalConfig() {
    // 初始化方法中校验cse.configurationSource.additionalUrls和cse.configurationSource.defaultFileName不能配置值
    MicroserviceConfigLoader loader = new MicroserviceConfigLoader();
    // 加载完成配置文件
	loader.loadAndSort();
    if (localConfig.size() > 0) {
      ConfigModel model = new ConfigModel();
      model.setConfig(localConfig);
      loader.getConfigModels().add(model);
    }

    LOGGER.info("create local config:");
    for (ConfigModel configModel : loader.getConfigModels()) {
      LOGGER.info(" {}.", configModel.getUrl());
    }
    // 获取环境变量和服务的配置信息
    ConcurrentCompositeConfiguration config = ConfigUtil.createLocalConfig(loader.getConfigModels());
    // 将loader的信息放入config中对应的配置中,对应的key为cse-microservice-config-loader
	// 在ConcurrentCompositeConfiguration中都会封装为其变量configList中的Configuration来源对象
	ConfigUtil.setMicroserviceConfigLoader(config, loader);
    return config;
  }

  // 根据加载的配置项,放入archives中进行管理
  public static ConcurrentCompositeConfiguration createLocalConfig(List<ConfigModel> configModelList) {
    ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration();

	// 将系统配置项包装为ConcurrentMapConfiguration织入ConcurrentCompositeConfiguration
    duplicateCseConfigToServicecomb(config,
        new ConcurrentMapConfiguration(new SystemConfiguration()),
        "configFromSystem");
    // 将当前服务的环境配置信息,加入ConcurrentCompositeConfiguration中
	// convertEnvVariable将其中包含_的配置项,将配置项名称中的_替换为.,重新放入source中
    duplicateCseConfigToServicecomb(config,
        convertEnvVariable(new ConcurrentMapConfiguration(new EnvironmentConfiguration())),
        "configFromEnvironment");
    // If there is extra configurations, add it into config.
    // 将spring的环境配置信息加入config中
	EXTRA_CONFIG_MAP.entrySet()
        .stream()
        .filter(mapEntry -> !mapEntry.getValue().isEmpty())
        .forEachOrdered(configMapEntry -> duplicateCseConfigToServicecomb(config,
            new ConcurrentMapConfiguration(configMapEntry.getValue()),
            configMapEntry.getKey()));
    // we have already copy the cse config to the serviceComb config when we load the config from local yaml files
    // hence, we do not need duplicate copy it.
    // 将microservice.yaml的配置值加入config中,由于此处的配置加载是本地配置加载,因此NeverStartPollingScheduler中什么都没做
	// MicroserviceConfigurationSource配置信息的加载更新逻辑,此处每次都会将所有的配置重新读取,返回全量的数据
	config.addConfiguration(new DynamicConfiguration(
            new MicroserviceConfigurationSource(configModelList), new NeverStartPollingScheduler()),
        "configFromYamlFile");
	// ConfigMapping.getConvertedMap将所有的value,以原因的value为key,原有的value为value新建一个Map
    duplicateCseConfigToServicecombAtFront(config,
        new ConcurrentMapConfiguration(ConfigMapping.getConvertedMap(config)),
        "configFromMapping");
    return config;
  }

  public static AbstractConfiguration convertEnvVariable(AbstractConfiguration source) {
    Iterator<String> keys = source.getKeys();
    while (keys.hasNext()) {
      String key = keys.next();
      String[] separatedKey = key.split(CONFIG_KEY_SPLITER);
      if (separatedKey.length == 1) {
        continue;
      }
      String newKey = String.join(".", separatedKey);
      source.addProperty(newKey, source.getProperty(key));
    }
    return source;
  }

  //inject a copy of servicecomb.xxx for cse.xxx
  // 此处进行配置项的装换,将cse.开头的配置,换为以servicecomb.开头后重新放入source中
  private static void duplicateCseConfigToServicecomb(AbstractConfiguration source) {
    Iterator<String> keys = source.getKeys();
    while (keys.hasNext()) {
      String key = keys.next();
	  // 只有以cse.开头的配置项才会在此处加载
      if (!key.startsWith(CONFIG_CSE_PREFIX)) {
        continue;
      }

      String servicecombKey = CONFIG_SERVICECOMB_PREFIX + key.substring(key.indexOf(".") + 1);
      if (!source.containsKey(servicecombKey)) {
        source.addProperty(servicecombKey, source.getProperty(key));
      } else {
        LOGGER
            .warn(
                "Key {} with an ambiguous item {} exists, it's recommended to use only one of them.",
                key, servicecombKey);
      }
    }
  }

  private static void duplicateCseConfigToServicecomb(ConcurrentCompositeConfiguration compositeConfiguration,
      AbstractConfiguration source,
      String sourceName) {
    duplicateCseConfigToServicecomb(source);

    compositeConfiguration.addConfiguration(source, sourceName);
  }

  private static void duplicateCseConfigToServicecombAtFront(ConcurrentCompositeConfiguration compositeConfiguration,
      AbstractConfiguration source,
      String sourceName) {
    duplicateCseConfigToServicecomb(source);

    compositeConfiguration.addConfigurationAtFront(source, sourceName);
  }

  private static ConfigCenterConfigurationSource createConfigCenterConfigurationSource(
      Configuration localConfiguration) {
	// 此处cse提供了扩展点ConfigCenterConfigurationSource,后续进行讨论,运行业务自定义加载自有的配置中心加载对应的配置
    ConfigCenterConfigurationSource configCenterConfigurationSource =
        SPIServiceUtils.getTargetService(ConfigCenterConfigurationSource.class);
    if (null == configCenterConfigurationSource) {
      LOGGER.info(
          "config center SPI service can not find, skip to load configuration from config center");
      return null;
    }

    if (!configCenterConfigurationSource.isValidSource(localConfiguration)) {
      LOGGER.warn("Config Source serverUri is not correctly configured.");
      return null;
    }
    return configCenterConfigurationSource;
  }

  private static void createDynamicWatchedConfiguration(
      ConcurrentCompositeConfiguration localConfiguration,
      ConfigCenterConfigurationSource configCenterConfigurationSource) {
    ConcurrentMapConfiguration injectConfig = new ConcurrentMapConfiguration();
    localConfiguration.addConfigurationAtFront(injectConfig, "extraInjectConfig");
    configCenterConfigurationSource.addUpdateListener(new ServiceCombPropertyUpdateListener(injectConfig));

    DynamicWatchedConfiguration configFromConfigCenter =
        new DynamicWatchedConfiguration(configCenterConfigurationSource);
    duplicateCseConfigToServicecomb(configFromConfigCenter);
    localConfiguration.addConfigurationAtFront(configFromConfigCenter, "configCenterConfig");
  }

  public static AbstractConfiguration createDynamicConfig() {
    ConcurrentCompositeConfiguration compositeConfig = ConfigUtil.createLocalConfig();
    ConfigCenterConfigurationSource configCenterConfigurationSource =
        createConfigCenterConfigurationSource(compositeConfig);
    if (configCenterConfigurationSource != null) {
      createDynamicWatchedConfiguration(compositeConfig, configCenterConfigurationSource);
    }
    return compositeConfig;
  }

  public static void installDynamicConfig() {
    // 调用archives的ConfigurationManager管理类,业务自定义的配置信息是否已经安装
    if (ConfigurationManager.isConfigurationInstalled()) {
      LOGGER.warn("Configuration installed by others, will ignore this configuration.");
      return;
    }
    // 加载本地的配置项
    ConcurrentCompositeConfiguration compositeConfig = ConfigUtil.createLocalConfig();
    // 此处加载ConfigCenterConfigurationSource的实现类
	ConfigCenterConfigurationSource configCenterConfigurationSource =
        createConfigCenterConfigurationSource(compositeConfig);
    if (configCenterConfigurationSource != null) {
      createDynamicWatchedConfiguration(compositeConfig, configCenterConfigurationSource);
    }
    // 将目前的配置加载到ConfigurationManager中
    ConfigurationManager.install(compositeConfig);

    if (configCenterConfigurationSource != null) {
      configCenterConfigurationSource.init(compositeConfig);
    }
  }

  public static void destroyConfigCenterConfigurationSource() {
    SPIServiceUtils.getAllService(ConfigCenterConfigurationSource.class).forEach(source -> {
      try {
        source.destroy();
      } catch (Throwable e) {
        LOGGER.error("Failed to destroy {}", source.getClass().getName());
      }
    });
  }

  public static void addExtraConfig(String extraConfigName, Map<String, Object> extraConfig) {
    EXTRA_CONFIG_MAP.put(extraConfigName, extraConfig);
  }

  public static void clearExtraConfig() {
    EXTRA_CONFIG_MAP.clear();
  }

  private static class ServiceCombPropertyUpdateListener implements WatchedUpdateListener {

    private final ConcurrentMapConfiguration injectConfig;

    ServiceCombPropertyUpdateListener(ConcurrentMapConfiguration injectConfig) {
      this.injectConfig = injectConfig;
    }

    @Override
    public void updateConfiguration(WatchedUpdateResult watchedUpdateResult) {
      Map<String, Object> adds = watchedUpdateResult.getAdded();
      if (adds != null) {
        for (String add : adds.keySet()) {
          if (add.startsWith(CONFIG_CSE_PREFIX)) {
            String key = CONFIG_SERVICECOMB_PREFIX + add.substring(add.indexOf(".") + 1);
            injectConfig.addProperty(key, adds.get(add));
          }
        }
      }

      Map<String, Object> deletes = watchedUpdateResult.getDeleted();
      if (deletes != null) {
        for (String delete : deletes.keySet()) {
          if (delete.startsWith(CONFIG_CSE_PREFIX)) {
            injectConfig.clearProperty(CONFIG_SERVICECOMB_PREFIX + delete.substring(delete.indexOf(".") + 1));
          }
        }
      }

      Map<String, Object> changes = watchedUpdateResult.getChanged();
      if (changes != null) {
        for (String change : changes.keySet()) {
          if (change.startsWith(CONFIG_CSE_PREFIX)) {
            String key = CONFIG_SERVICECOMB_PREFIX + change.substring(change.indexOf(".") + 1);
            injectConfig.setProperty(key, changes.get(change));
          }
        }
      }
    }
  }

  @SuppressWarnings("unchecked")
  public static ConcurrentHashMap<String, DynamicProperty> getAllDynamicProperties() {
    try {
      return (ConcurrentHashMap<String, DynamicProperty>) FieldUtils
          .readDeclaredStaticField(DynamicProperty.class, "ALL_PROPS", true);
    } catch (IllegalAccessException e) {
      throw new IllegalStateException(e);
    }
  }

  @SuppressWarnings("unchecked")
  public static CopyOnWriteArraySet<Runnable> getCallbacks(DynamicProperty property) {
    try {
      return (CopyOnWriteArraySet<Runnable>) FieldUtils.readDeclaredField(property, "callbacks", true);
    } catch (IllegalAccessException e) {
      throw new IllegalStateException(e);
    }
  }
}

org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader进行服务配置的加载:

public class MicroserviceConfigLoader extends YAMLConfigLoader {
  private static final Logger LOGGER = LoggerFactory.getLogger(MicroserviceConfigLoader.class);

  private static final String ADDITIONAL_CONFIG_URL = "servicecomb.configurationSource.additionalUrls";

  private static final String DEFAULT_FILE_NAME = "servicecomb.configurationSource.defaultFileName";

  /**
   * Default configuration file name to be used by default constructor. This file should
   * be on the classpath. The file name can be overridden by the value of system property
   * <code>configurationSource.defaultFileName</code>
   */
  private static final String DEFAULT_CONFIG_FILE_NAME = "microservice.yaml";

  public MicroserviceConfigLoader() {
    // Help to resolve incompatible changes. Can be deleted in future.
    if (!StringUtils.isEmpty(System.getProperty("cse.configurationSource.additionalUrls"))) {
      throw new IllegalArgumentException("-Dcse.configurationSource.additionalUrls"
          + " has been replaced with -D" + ADDITIONAL_CONFIG_URL + ", please change it and restart.");
    }
    if (!StringUtils.isEmpty(System.getProperty("cse.configurationSource.defaultFileName"))) {
      throw new IllegalArgumentException("-Dcse.configurationSource.additionalUrls"
          + " has been replaced with -D" + DEFAULT_FILE_NAME + ", please change it and restart.");
    }
  }

  public void loadAndSort() {
    try {
	  // 配置文件的名称,默认为microservice.yaml
      String configFileFromClasspath =
          System.getProperty(DEFAULT_FILE_NAME) == null ? DEFAULT_CONFIG_FILE_NAME
              : System.getProperty(DEFAULT_FILE_NAME);
      // 此处初始化了configModels变量
	  super.load(configFileFromClasspath);
	  // 加载servicecomb.configurationSource.additionalUrls配置路径的配置值
      loadAdditionalConfig();

      if (configModels.isEmpty()) {
        LOGGER.warn("No URLs will be polled as dynamic configuration sources.");
        LOGGER.warn(
            "To enable URLs as dynamic configuration sources, define System property {} or make {} available on classpath.",
            ADDITIONAL_CONFIG_URL,
            configFileFromClasspath);
      }
      // 按照order进行重新的排序
      sort();
    } catch (IOException e) {
      throw new ServiceCombException("Failed to load microservice config", e);
    }
  }

  private void loadAdditionalConfig() throws IOException {
    String strUrls = System.getProperty(ADDITIONAL_CONFIG_URL);
    if (StringUtils.isEmpty(strUrls)) {
      return;
    }

    for (String strUrl : strUrls.split(",")) {
      URL url = new URL(strUrl);
      ConfigModel configModel = load(url);
      configModels.add(configModel);
    }
  }
}

org.apache.servicecomb.config.archaius.sources.YAMLConfigLoader实现了yaml加载的功能:

public class YAMLConfigLoader extends AbstractConfigLoader {
  @SuppressWarnings("unchecked")
  @Override
  protected Map<String, Object> loadData(URL url) throws IOException {
    Yaml yaml = new Yaml();

    try (InputStream inputStream = url.openStream()) {
      return yaml.loadAs(inputStream, Map.class);
    }
  }
}

YAMLConfigLoader的基类是AbstractConfigLoader,实现逻辑如下:

public abstract class AbstractConfigLoader {
  private static final Logger LOGGER = LoggerFactory.getLogger(AbstractConfigLoader.class);

  private static final String ORDER_KEY = "servicecomb-config-order";

  protected final List<ConfigModel> configModels = new ArrayList<>();

  public List<ConfigModel> getConfigModels() {
    return configModels;
  }

  public void load(String resourceName) throws IOException {
    loadFromClassPath(resourceName);
  }

  protected void loadFromClassPath(String resourceName) throws IOException {
    List<URL> urlList = findURLFromClassPath(resourceName);
    for (URL url : urlList) {
      ConfigModel configModel = load(url);
      configModels.add(configModel);
    }
  }

  // 逐一加载microservice.yaml配置文件
  public ConfigModel load(URL url) throws IOException {
    // 将microservice.yaml加载为嵌套Map的形式
	Map<String, Object> config = loadData(url);
    // load a empty or all commented yaml, will get a null map
    // this is not an error
    if (config == null) {
      config = new LinkedHashMap<>();
    }
    // 将加载的数据和路径封装为ConfigModel对象
    ConfigModel configModel = new ConfigModel();
    configModel.setUrl(url);
    configModel.setConfig(config);

	// ORDER_KEY的值为servicecomb-config-order
    Object objOrder = config.get(ORDER_KEY);
    if (objOrder == null) {
      // compatible check 未来不再支持,如果配置了打印报错信息
      objOrder = config.get("cse-config-order");
      if (objOrder != null) {
        LOGGER.error("cse-config-order will not be supported in future, please change it to servicecomb-config-order");
      }
    }

    if (objOrder != null) {
      if (Integer.class.isInstance(objOrder)) {
        configModel.setOrder((int) objOrder);
      } else {
        configModel.setOrder(Integer.parseInt(String.valueOf(objOrder)));
      }
    }
    return configModel;
  }

  protected abstract Map<String, Object> loadData(URL url) throws IOException;

  // 从当前jar包中扫描microservice.yaml文件
  protected List<URL> findURLFromClassPath(String resourceName) throws IOException {
    List<URL> urlList = new ArrayList<>();

    ClassLoader loader = JvmUtils.findClassLoader();
    Enumeration<URL> urls = loader.getResources(resourceName);
    while (urls.hasMoreElements()) {
      urlList.add(urls.nextElement());
    }
    // 当前本地启动包含两个microservice.yaml文件
	// file:/D:/WorkProject/servicecomb-java-chassis/samples/auth-sample/auth-provider/target/classes/microservice.yaml
	// file:/D:/WorkProject/servicecomb-java-chassis/core/target/classes/microservice.yaml
    return urlList;
  }

  private class ConfigModelWrapper {
    ConfigModel model;

    int addOrder;
  }

  // sort rule:
  // 1.files in jar
  // 2.smaller order
  // 3.add to list earlier
  protected void sort() {
    List<ConfigModelWrapper> list = new ArrayList<>(configModels.size());
    for (int idx = 0; idx < configModels.size(); idx++) {
      ConfigModelWrapper wrapper = new ConfigModelWrapper();
      wrapper.model = configModels.get(idx);
      wrapper.addOrder = idx;
      list.add(wrapper);
    }

    list.sort(this::doSort);

    for (int idx = 0; idx < configModels.size(); idx++) {
      configModels.set(idx, list.get(idx).model);
    }
  }

  private int doSort(ConfigModelWrapper w1, ConfigModelWrapper w2) {
    ConfigModel m1 = w1.model;
    ConfigModel m2 = w2.model;
    boolean isM1Jar = ResourceUtils.isJarURL(m1.getUrl());
    boolean isM2Jar = ResourceUtils.isJarURL(m2.getUrl());
    if (isM1Jar != isM2Jar) {
      if (isM1Jar) {
        return -1;
      }

      return 1;
    }
    // min order load first
    int result = Integer.compare(m1.getOrder(), m2.getOrder());
    if (result != 0) {
      return result;
    }

    return doFinalSort(w1, w2);
  }

  private int doFinalSort(ConfigModelWrapper w1, ConfigModelWrapper w2) {
    return Integer.compare(w1.addOrder, w2.addOrder);
  }
}

Spring占位符的解析

org.apache.servicecomb.config.LastPropertyPlaceholderConfigurer进行spring占位符的解析:

// do not implements PriorityOrdered, must be Ordered
// because this bean must run after PropertyPlaceholderConfigurer
// this class's purpose: when asked to resolve placeholder, then throw exception directly
// 本方法的目的是让spring在解析占位符的时候,抛出异常,?,目前不理解
@Component
public class LastPropertyPlaceholderConfigurer implements BeanFactoryPostProcessor, Ordered {
  @Override
  public int getOrder() {
    return Ordered.LOWEST_PRECEDENCE;
  }

  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	new PropertyPlaceholderConfigurer().postProcessBeanFactory(beanFactory);
  }
}

属性注入

注解

CSE提供了InjectProperties和InjectProperty注解。

InjectProperties注解的参数如下:

配置名称默认值说明
prefix""绑定的配置的前缀

InjectProperty注解的参数如下:

配置名称默认值说明
prefix""绑定的配置的前缀
keys{}配置的名称
defaultValue""默认值

配置解析触发类

org.apache.servicecomb.config.priority.PriorityPropertyManager触发配置项的解析:

// 在SCBEngine类中新建PriorityPropertyManager对象
public class PriorityPropertyManager {
  private ConfigurationListener configurationListener = this::configurationListener;

  private Map<PriorityProperty<?>, PriorityProperty<?>> priorityPropertyMap = new ConcurrentHashMapEx<>();

  private Map<Object, List<PriorityProperty<?>>> configObjectMap = new ConcurrentHashMapEx<>();

  // will be reset to null after register or unregister
  // and build when configuration changed
  private Map<String, List<PriorityProperty<?>>> keyCache;

  // 对应的构造方法
  public PriorityPropertyManager() {
    // make sure create a DynamicPropertyFactory instance
    // otherwise will cause wrong order of configurationListeners
    DynamicPropertyFactory.getInstance();
    // 添加配置监听器
    ConfigurationManager.getConfigInstance().addConfigurationListener(configurationListener);
  }

  public void close() {
    ConfigurationManager.getConfigInstance().removeConfigurationListener(configurationListener);
  }
    // 使用此处的监听,当配置变化时,会触发对应的callback回调函数
  public synchronized void configurationListener(ConfigurationEvent event) {
    // 如果配置变化在更新前,直接退出
	if (event.isBeforeUpdate()) {
      return;
    }
    // 将更新配置的key放入keyCache中
    if (keyCache == null) {
      keyCache = new ConcurrentHashMapEx<>();
      updateCache(priorityPropertyMap.values());
      configObjectMap.values().stream().forEach(this::updateCache);
    }

    if (event.getPropertyName() != null) {
      keyCache.getOrDefault(event.getPropertyName(), Collections.emptyList()).stream()
          .forEach(p -> p.updateFinalValue(false));
      return;
    }

    // event like add configuration source, need to make a global refresh
    keyCache.values().stream().flatMap(Collection::stream).forEach(p -> p.updateFinalValue(false));
  }

  private void updateCache(Collection<PriorityProperty<?>> properties) {
    for (PriorityProperty<?> priorityProperty : properties) {
      for (String key : priorityProperty.getPriorityKeys()) {
        keyCache.computeIfAbsent(key, k -> new ArrayList<>()).add(priorityProperty);
      }
      priorityProperty.updateFinalValue(false);
    }
  }

  public Map<PriorityProperty<?>, PriorityProperty<?>> getPriorityPropertyMap() {
    return priorityPropertyMap;
  }

  public Map<Object, List<PriorityProperty<?>>> getConfigObjectMap() {
    return configObjectMap;
  }

  private synchronized void registerPriorityProperty(PriorityProperty<?> property) {
    priorityPropertyMap.put(property, property);
    keyCache = null;
  }

  private synchronized void registerConfigObject(Object configObject, List<PriorityProperty<?>> properties) {
    // configObject类型为OperationConfig,properties为解析出的对象与值
	configObjectMap.put(configObject, properties);
    keyCache = null;
  }

  public synchronized void unregisterPriorityProperty(PriorityProperty<?> property) {
    priorityPropertyMap.remove(property);
    keyCache = null;
  }

  public synchronized void unregisterConfigObject(Object configObject) {
    if (configObject == null) {
      return;
    }

    configObjectMap.remove(configObject);
    keyCache = null;
  }

  // OperationMeta的this.config = SCBEngine.getInstance().getPriorityPropertyManager().createConfigObject语句会调用的此处
  // cls对应的为org.apache.servicecomb.core.definition.OperationConfig
  // kvs中的值为["op-any-priority",["${schema}.${operation}","${schema}"],"consumer-op-any_priority",["${service}.${schema}.${operation}","${service}.${schema}","${service}"],"producer-op-any_priority",{"$ref":"$[1]"},"op-priority",[".${schema}.${operation}",".${schema}",""],"consumer-op-priority",[".${service}.${schema}.${operation}",".${service}.${schema}",".${service}",""],"producer-op-priority",{"$ref":"$[7]"},"consumer-producer","Provider","consumer-provider","Provider","service","auth-provider","schema","RestProviderImpl","operation","delete"]
  public <T> T createConfigObject(Class<T> cls, Object... kvs) {
    Map<String, Object> parameters = new HashMap<>();
	// 将kvs数组转换为parameters Map对象
    for (int idx = 0; idx < kvs.length; idx += 2) {
      parameters.put(kvs[idx].toString(), kvs[idx + 1]);
    }
    // 
    return createConfigObject(cls, parameters);
  }

  public <T> T createConfigObject(Class<T> cls, Map<String, Object> parameters) {
    // 新建ConfigObjectFactory对象
    ConfigObjectFactory factory = new ConfigObjectFactory();
	// 新建对应的OperationConfig对象
    T configObject = factory.create(this, cls, parameters);
    // 将对象存入到configObjectMap中缓存起来
	registerConfigObject(configObject, factory.getPriorityProperties());
    return configObject;
  }

  // 对于调用priorityPropertyManager.newPriorityProperty(Boolean.class, null, defaultValue, keys);:
  // cls为java.lang.Boolean,invalidValue为null,defaultValue为false
  // priorityKeys为["servicecomb.metrics.Provider.invocation.slow.enabled.RestProviderImpl.delete","servicecomb.metrics.Provider.invocation.slow.enabled.RestProviderImpl","servicecomb.metrics.Provider.invocation.slow.enabled","servicecomb.Provider.invocation.slow.enabled.RestProviderImpl.delete","servicecomb.Provider.invocation.slow.enabled.RestProviderImpl","servicecomb.Provider.invocation.slow.enabled"]
  public <T> PriorityProperty<T> newPriorityProperty(Type cls, T invalidValue, T defaultValue,
      String... priorityKeys) {
    return new PriorityProperty<>(cls, invalidValue, defaultValue, priorityKeys);
  }

  public <T> PriorityProperty<T> createPriorityProperty(Type cls, T invalidValue, T defaultValue,
      String... priorityKeys) {
    PriorityProperty<T> priorityProperty = new PriorityProperty<>(cls, invalidValue, defaultValue, priorityKeys);
    registerPriorityProperty(priorityProperty);
    return priorityProperty;
  }
}

org.apache.servicecomb.config.priority.PriorityProperty配置信息类:

public class PriorityProperty<T> {
  private static final Logger LOGGER = LoggerFactory.getLogger(PriorityProperty.class);

  // priorityKeys[0] has the highest priority
  private final String[] priorityKeys;

  private final String joinedPriorityKeys;

  // when got invalid value will try next level
  // null always be a invalid value
  private final T invalidValue;

  // when got invalid value by lowest level, will use defaultValue
  private final T defaultValue;

  private DynamicProperty[] properties;

  private T finalValue;

  private Function<DynamicProperty, T> internalValueReader;

  private Consumer<T> callback = v -> {
  };

  // 对于boolean类型:
  // type值为java.lang.Boolean,invalidValue为null,defaultValue为false
  // priorityKeys为["servicecomb.metrics.Provider.invocation.slow.enabled.RestProviderImpl.delete","servicecomb.metrics.Provider.invocation.slow.enabled.RestProviderImpl","servicecomb.metrics.Provider.invocation.slow.enabled","servicecomb.Provider.invocation.slow.enabled.RestProviderImpl.delete","servicecomb.Provider.invocation.slow.enabled.RestProviderImpl","servicecomb.Provider.invocation.slow.enabled"]
  @SuppressWarnings("unchecked")
  PriorityProperty(Type type, T invalidValue, T defaultValue, String... priorityKeys) {
    // 
	internalValueReader = collectReader(type);

    this.priorityKeys = priorityKeys;
    this.joinedPriorityKeys = Arrays.toString(priorityKeys);
    this.invalidValue = invalidValue;
    this.defaultValue = defaultValue;

	// 对应的key封装为archives的DynamicProperty对象
    properties = new DynamicProperty[priorityKeys.length];
    for (int idx = 0; idx < priorityKeys.length; idx++) {
      String key = priorityKeys[idx].trim();
      properties[idx] = DynamicProperty.getInstance(key);
    }
    updateFinalValue(true);
  }

  private Function<DynamicProperty, T> collectReader(Type type) {
    if (type == int.class || type == Integer.class) {
      return this::readInt;
    }

    if (type == long.class || type == Long.class) {
      return this::readLong;
    }

    if (type == String.class) {
      return this::readString;
    }

    if (type == boolean.class || type == Boolean.class) {
      return this::readBoolean;
    }

    if (type == double.class || type == Double.class) {
      return this::readDouble;
    }

    if (type == float.class || type == Float.class) {
      return this::readFloat;
    }

    throw new IllegalStateException("not support, type=" + type.getTypeName());
  }

  @SuppressWarnings("unchecked")
  protected T readInt(DynamicProperty property) {
    return (T) property.getInteger();
  }

  @SuppressWarnings("unchecked")
  protected T readLong(DynamicProperty property) {
    return (T) property.getLong();
  }

  @SuppressWarnings("unchecked")
  protected T readString(DynamicProperty property) {
    return (T) property.getString();
  }

  @SuppressWarnings("unchecked")
  protected T readBoolean(DynamicProperty property) {
    return (T) property.getBoolean();
  }

  @SuppressWarnings("unchecked")
  protected T readDouble(DynamicProperty property) {
    return (T) property.getDouble();
  }

  @SuppressWarnings("unchecked")
  protected T readFloat(DynamicProperty property) {
    return (T) property.getFloat();
  }

  public String[] getPriorityKeys() {
    return priorityKeys;
  }

  public T getDefaultValue() {
    return defaultValue;
  }

  public DynamicProperty[] getProperties() {
    return properties;
  }

  synchronized void updateFinalValue(boolean init) {
    T lastValue = finalValue;

    String effectiveKey = "default value";
    T value = defaultValue;
    for (DynamicProperty property : properties) {
      T propValue = internalValueReader.apply(property);
      if (propValue == null || propValue.equals(invalidValue)) {
        continue;
      }

      effectiveKey = property.getName();
      value = propValue;
      break;
    }

    if (Objects.equals(lastValue, value)) {
      return;
    }

    if (init) {
      LOGGER.debug("config inited, \"{}\" set to {}, effective key is \"{}\".",
          joinedPriorityKeys, value, effectiveKey);
    } else {
      LOGGER.info("config changed, \"{}\" changed from {} to {}, effective key is \"{}\".",
          joinedPriorityKeys, finalValue, value, effectiveKey);
    }
    finalValue = value;
    callback.accept(finalValue);
  }

  public T getValue() {
    return finalValue;
  }

  public void setCallback(Consumer<T> callback) {
    this.callback = callback;
    callback.accept(finalValue);
  }
}

org.apache.servicecomb.config.inject.ConfigObjectFactory的实现如下:

ConfigObjectFactory会进行注解的解析,解析InjectProperty和InjectProperties注解的信息。

/**
 * must create by PriorityPropertyManager<br>
 *   or register to PriorityPropertyManager manually<br>
 * <br>
 * ${} or ${not-exist-key} is valid key in archaius<br>
 * so this wrapper mechanism will not throw exception even can not find value by placeholder
 */
public class ConfigObjectFactory {
  private PriorityPropertyManager priorityPropertyManager;

  private Class<?> cls;

  private Map<String, Object> parameters;

  private Object instance;

  private String prefix = "";

  private List<PriorityProperty<?>> priorityProperties = new ArrayList<>();

  // priorityPropertyManager为传入的调用类的信息
  // cls为org.apache.servicecomb.core.definition.OperationConfig类
  // parameters为对应的传入参数,对应上一层的调用入参
  @SuppressWarnings("unchecked")
  public <T> T create(PriorityPropertyManager priorityPropertyManager, Class<T> cls, Map<String, Object> parameters) {

	this.priorityPropertyManager = priorityPropertyManager;
    this.cls = cls;
    this.parameters = parameters;

    try {
	  // 新建对应的OperationConfig cls对象
      instance = cls.newInstance();
    } catch (Throwable e) {
      throw new IllegalStateException("create config object failed, class=" + cls.getName(), e);
    }
    // 解析配置前置头,为servicecomb.
    initPrefix();
    doCreate();

    return (T) instance;
  }

  public List<PriorityProperty<?>> getPriorityProperties() {
    return priorityProperties;
  }

  // 解析OperationConfig中的InjectProperties注解信息
  private void initPrefix() {
    InjectProperties injectProperties = cls.getAnnotation(InjectProperties.class);
    if (injectProperties == null) {
      return;
    }
    // 类上使用的InjectProperties注解中的prefix的值为servicecomb
    String prefix = injectProperties.prefix();
    if (!prefix.isEmpty()) {
      this.prefix = prefix + ".";
    }
  }

  private void doCreate() {
    // 使用jackson解析OperationConfig类对象中的字段信息
    JavaType javaType = TypeFactory.defaultInstance().constructType(cls);
    BeanDescription beanDescription = JsonUtils.OBJ_MAPPER.getSerializationConfig().introspect(javaType);
	// beanDescription.findProperties()返回每一个字段的描述信息
	// propertyDefinition的类型为POJOPropertyBuilder
    for (BeanPropertyDefinition propertyDefinition : beanDescription.findProperties()) {
      if (propertyDefinition.getField() == null) {
        continue;
      }
      // 字段有对应的setter方法,并且字段不是public
      if (propertyDefinition.getSetter() == null && !propertyDefinition.getField().isPublic()) {
        continue;
      }
      // 将所有的字段逐一封装为Setter接口的形式
      Setter<Object, Object> setter = propertyDefinition.getSetter() == null ?
          LambdaMetafactoryUtils.createSetter(propertyDefinition.getField().getAnnotated()) :
          LambdaMetafactoryUtils.createLambda(propertyDefinition.getSetter().getAnnotated(), Setter.class);

      PriorityProperty<?> priorityProperty = createPriorityProperty(propertyDefinition.getField().getAnnotated());
      // 此处,增加回调方法,在配置值改变时,调用instance的set方法,将对应的值存入对应的值
	  priorityProperty.setCallback(value -> setter.set(instance, value));
      priorityProperties.add(priorityProperty);
    }
  }

  // 创建PriorityProperty对象
  private PriorityProperty<?> createPriorityProperty(Field field) {
    // 解析对应的InjectProperty注解,获取其中配置的key对应的配置信息
	String[] keys = collectPropertyKeys(field);
    // 对于slowInvocationEnabled字段其类型为boolean
    Class<?> fieldCls = field.getType();
    switch (fieldCls.getName()) {
      case "int":
        return createIntProperty(field, keys, 0);
      case "java.lang.Integer":
        return createIntProperty(field, keys, null);
      case "long":
        return createLongProperty(field, keys, 0L);
      case "java.lang.Long":
        return createLongProperty(field, keys, null);
      case "java.lang.String":
        return createStringProperty(field, keys);
      case "float":
        return createFloatProperty(field, keys, 0f);
      case "java.lang.Float":
        return createFloatProperty(field, keys, null);
      case "double":
        return createDoubleProperty(field, keys, 0.0);
      case "java.lang.Double":
        return createDoubleProperty(field, keys, null);
      case "boolean":
        return createBooleanProperty(field, keys, false);
      case "java.lang.Boolean":
        return createBooleanProperty(field, keys, null);
    }

    throw new IllegalStateException("not support, field=" + field);
  }

  private PriorityProperty<?> createStringProperty(Field field, String[] keys) {
    String defaultValue = null;
    InjectProperty injectProperty = field.getAnnotation(InjectProperty.class);
    if (injectProperty != null) {
      if (!injectProperty.defaultValue().isEmpty()) {
        defaultValue = injectProperty.defaultValue();
      }
    }

    return priorityPropertyManager.newPriorityProperty(String.class, null, defaultValue, keys);
  }

  private PriorityProperty<?> createDoubleProperty(Field field, String[] keys, Double defaultValue) {
    InjectProperty injectProperty = field.getAnnotation(InjectProperty.class);
    if (injectProperty != null) {
      if (!injectProperty.defaultValue().isEmpty()) {
        defaultValue = Double.parseDouble(injectProperty.defaultValue());
      }
    }

    return priorityPropertyManager.newPriorityProperty(Double.class, null, defaultValue, keys);
  }

  private PriorityProperty<?> createFloatProperty(Field field, String[] keys, Float defaultValue) {
    InjectProperty injectProperty = field.getAnnotation(InjectProperty.class);
    if (injectProperty != null) {
      if (!injectProperty.defaultValue().isEmpty()) {
        defaultValue = Float.parseFloat(injectProperty.defaultValue());
      }
    }

    return priorityPropertyManager.newPriorityProperty(Float.class, null, defaultValue, keys);
  }

  // 将字段信息封装为PriorityProperty对象,利用archives的配置管理能力
  private PriorityProperty<?> createBooleanProperty(Field field, String[] keys, Boolean defaultValue) {
    InjectProperty injectProperty = field.getAnnotation(InjectProperty.class);
    // 对于slowInvocationEnabled字段,注解存在
	if (injectProperty != null) {
      if (!injectProperty.defaultValue().isEmpty()) {
	    // defaultValue配置为false
        defaultValue = Boolean.parseBoolean(injectProperty.defaultValue());
      }
    }

    return priorityPropertyManager.newPriorityProperty(Boolean.class, null, defaultValue, keys);
  }

  private PriorityProperty<?> createLongProperty(Field field, String[] keys, Long defaultValue) {
    InjectProperty injectProperty = field.getAnnotation(InjectProperty.class);
    if (injectProperty != null) {
      if (!injectProperty.defaultValue().isEmpty()) {
        defaultValue = Long.parseLong(injectProperty.defaultValue());
      }
    }

    return priorityPropertyManager.newPriorityProperty(Long.class, null, defaultValue, keys);
  }

  private PriorityProperty<?> createIntProperty(Field field, String[] keys, Integer defaultValue) {
    InjectProperty injectProperty = field.getAnnotation(InjectProperty.class);
    if (injectProperty != null) {
      if (!injectProperty.defaultValue().isEmpty()) {
        defaultValue = Integer.parseInt(injectProperty.defaultValue());
      }
    }

    return priorityPropertyManager.newPriorityProperty(Integer.class, null, defaultValue, keys);
  }

  // 获取配置的key
  private String[] collectPropertyKeys(Field field) {
    // 开头为servicecomb.
    String propertyPrefix = prefix;
	// 字段的名称,此处以slowInvocationEnabled为例进行分析
    String[] keys = new String[] {field.getName()};
    // 获取字段的注解
	// 注解的信息为 prefix为空,defaultValue为false,keys为["metrics.${consumer-producer}.invocation.slow.enabled${op-priority}", "${consumer-producer}.invocation.slow.enabled${op-priority}"]
    InjectProperty injectProperty = field.getAnnotation(InjectProperty.class);
    if (injectProperty != null) {
      if (!injectProperty.prefix().isEmpty()) {
        propertyPrefix = injectProperty.prefix() + ".";
      }
      if (injectProperty.keys().length != 0) {
        // 获取对应的配置的keys参数,keys中为对应的配置项的名称
		keys = injectProperty.keys();
      }
    }

    List<String> finalKeys = new ArrayList<>();
	// 一一解析每一个配置项的值
	// 此处的parameters为this.config = SCBEngine.getInstance().getPriorityPropertyManager().createConfigObject传入的参数
	// 举例: {"consumer-op-priority":[".${service}.${schema}.${operation}",".${service}.${schema}",".${service}",""],"schema":"RestProviderImpl","consumer-op-any_priority":["${service}.${schema}.${operation}","${service}.${schema}","${service}"],"consumer-provider":"Provider","producer-op-any_priority":["${schema}.${operation}","${schema}"],"service":"auth-provider","producer-op-priority":[".${schema}.${operation}",".${schema}",""],"consumer-producer":"Provider","op-priority":[".${schema}.${operation}",".${schema}",""],"operation":"delete","op-any-priority":["${schema}.${operation}","${schema}"]}
	// key为 servicecomb.metrics.${consumer-producer}.invocation.slow.enabled${op-priority}
	// 解析的结果为: ["servicecomb.metrics.Provider.invocation.slow.enabled.RestProviderImpl.delete","servicecomb.metrics.Provider.invocation.slow.enabled.RestProviderImpl","servicecomb.metrics.Provider.invocation.slow.enabled"]
    for (String key : keys) {
      List<String> resolvedKeys = new PlaceholderResolver().replace(propertyPrefix + key, parameters);
      finalKeys.addAll(resolvedKeys);
    }
    // 此处将InjectProperty注解的key中的占位符进行解析
    return finalKeys.toArray(new String[finalKeys.size()]);
  }
}

org.apache.servicecomb.core.definition.OperationConfig的实现如下:

OperationConfig定义了很多的配置注入字段,定义了CSE服务的配置参数。

// InjectProperties设置配置的头均为servicecomb
@InjectProperties(prefix = "servicecomb")
public class OperationConfig {
  public static final List<String> CONSUMER_OP_ANY_PRIORITY = Arrays.asList(
      "${service}.${schema}.${operation}",
      "${service}.${schema}",
      "${service}");

  public static final List<String> PRODUCER_OP_ANY_PRIORITY = Arrays.asList(
      "${schema}.${operation}",
      "${schema}");

  public static final List<String> CONSUMER_OP_PRIORITY = Arrays.asList(
      ".${service}.${schema}.${operation}",
      ".${service}.${schema}",
      ".${service}",
      "");

  public static final List<String> PRODUCER_OP_PRIORITY = Arrays.asList(
      ".${schema}.${operation}",
      ".${schema}",
      "");

  @InjectProperty(keys = {"metrics.${consumer-producer}.invocation.slow.enabled${op-priority}",
      "${consumer-producer}.invocation.slow.enabled${op-priority}"}, defaultValue = "false")
  private boolean slowInvocationEnabled;

  @InjectProperty(keys = {"metrics.${consumer-producer}.invocation.slow.msTime${op-priority}",
      "${consumer-producer}.invocation.slow.msTime${op-priority}"}, defaultValue = "1000")
  private long msSlowInvocation;

  private long nanoSlowInvocation;

  /**
   * consumer request timeout
   */
  @InjectProperty(keys = {"request.${op-any-priority}.timeout", "request.timeout"}, defaultValue = "30000")
  private long msRequestTimeout;

  /**
   * whether to remove certain headers from the 3rd party invocations
   */
  @InjectProperty(keys = {"request.clientRequestHeaderFilterEnabled${consumer-op-priority}"}, defaultValue = "true")
  private boolean clientRequestHeaderFilterEnabled = true;

  /**
   * producer wait in thread pool timeout
   */
  @InjectProperty(keys = {
      "Provider.requestWaitInPoolTimeout${op-priority}",
      "highway.server.requestWaitInPoolTimeout"}, defaultValue = "30000")
  private long msHighwayRequestWaitInPoolTimeout;

  private long nanoHighwayRequestWaitInPoolTimeout;

  @InjectProperty(keys = {
      "Provider.requestWaitInPoolTimeout${op-priority}",
      "rest.server.requestWaitInPoolTimeout"}, defaultValue = "30000")
  private long msRestRequestWaitInPoolTimeout;

  private long nanoRestRequestWaitInPoolTimeout;

  public boolean isSlowInvocationEnabled() {
    return slowInvocationEnabled;
  }

  public void setSlowInvocationEnabled(boolean slowInvocationEnabled) {
    this.slowInvocationEnabled = slowInvocationEnabled;
  }

  public long getMsSlowInvocation() {
    return msSlowInvocation;
  }

  public void setMsSlowInvocation(long msSlowInvocation) {
    this.msSlowInvocation = msSlowInvocation;
    this.nanoSlowInvocation = TimeUnit.MILLISECONDS.toNanos(msSlowInvocation);
  }

  public long getNanoSlowInvocation() {
    return nanoSlowInvocation;
  }

  public long getMsRequestTimeout() {
    return msRequestTimeout;
  }

  public void setMsRequestTimeout(long msRequestTimeout) {
    this.msRequestTimeout = msRequestTimeout;
  }

  public long getMsHighwayRequestWaitInPoolTimeout() {
    return msHighwayRequestWaitInPoolTimeout;
  }

  public void setMsHighwayRequestWaitInPoolTimeout(long msHighwayRequestWaitInPoolTimeout) {
    this.msHighwayRequestWaitInPoolTimeout = msHighwayRequestWaitInPoolTimeout;
    this.nanoHighwayRequestWaitInPoolTimeout = TimeUnit.MILLISECONDS.toNanos(msHighwayRequestWaitInPoolTimeout);
  }

  public long getNanoHighwayRequestWaitInPoolTimeout() {
    return nanoHighwayRequestWaitInPoolTimeout;
  }

  public long getMsRestRequestWaitInPoolTimeout() {
    return msRestRequestWaitInPoolTimeout;
  }

  public void setMsRestRequestWaitInPoolTimeout(long msRestRequestWaitInPoolTimeout) {
    this.msRestRequestWaitInPoolTimeout = msRestRequestWaitInPoolTimeout;
    this.nanoRestRequestWaitInPoolTimeout = TimeUnit.MILLISECONDS.toNanos(msRestRequestWaitInPoolTimeout);
  }

  public long getNanoRestRequestWaitInPoolTimeout() {
    return nanoRestRequestWaitInPoolTimeout;
  }

  public boolean isClientRequestHeaderFilterEnabled() {
    return clientRequestHeaderFilterEnabled;
  }

  public void setClientRequestHeaderFilterEnabled(boolean clientRequestHeaderFilterEnabled) {
    this.clientRequestHeaderFilterEnabled = clientRequestHeaderFilterEnabled;
  }
}

org.apache.servicecomb.foundation.common.utils.LambdaMetafactoryUtils创建通过反射设置类字段的方法:

public final class LambdaMetafactoryUtils {
  private static Field allowedModesField;

  private static final int ALL_MODES = (MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
      | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC);

  private static final Lookup LOOKUP = MethodHandles.lookup();

  private static final Map<Class<?>, Class<?>> GETTER_MAP = new HashMap<>();

  private static final Map<Class<?>, Class<?>> SETTER_MAP = new HashMap<>();

  static {
    enhanceLambda();
    initGetterSetterMap();
  }

  private static void initGetterSetterMap() {
    GETTER_MAP.put(boolean.class, BoolGetter.class);
    GETTER_MAP.put(byte.class, ByteGetter.class);
    GETTER_MAP.put(short.class, ShortGetter.class);
    GETTER_MAP.put(int.class, IntGetter.class);
    GETTER_MAP.put(long.class, LongGetter.class);
    GETTER_MAP.put(float.class, FloatGetter.class);
    GETTER_MAP.put(double.class, DoubleGetter.class);

    SETTER_MAP.put(boolean.class, BoolSetter.class);
    SETTER_MAP.put(byte.class, ByteSetter.class);
    SETTER_MAP.put(short.class, ShortSetter.class);
    SETTER_MAP.put(int.class, IntSetter.class);
    SETTER_MAP.put(long.class, LongSetter.class);
    SETTER_MAP.put(float.class, FloatSetter.class);
    SETTER_MAP.put(double.class, DoubleSetter.class);
  }

  private static void enhanceLambda() {
    try {
      Field modifiersField = Field.class.getDeclaredField("modifiers");
      modifiersField.setAccessible(true);

      allowedModesField = Lookup.class.getDeclaredField("allowedModes");
      allowedModesField.setAccessible(true);
      int modifiers = allowedModesField.getModifiers();
      modifiersField.setInt(allowedModesField, modifiers & ~Modifier.FINAL);
    } catch (Throwable e) {
      throw new IllegalStateException("Failed to init LambdaMetafactoryUtils.", e);
    }
  }

  private LambdaMetafactoryUtils() {
  }

  // 找到对应的abstract method方法
  // functionalInterface对应的是Setter.class对象
  // public interface Setter<C, F> {
  //   void set(C instance, F value);
  //}
  protected static Method findAbstractMethod(Class<?> functionalInterface) {
    for (Method method : functionalInterface.getMethods()) {
	  // 接口对应的方法为abstract方法
      if ((method.getModifiers() & Modifier.ABSTRACT) != 0) {
        return method;
      }
    }

    return null;
  }

  @SuppressWarnings("unchecked")
  public static <T> T createLambda(Object instance, Method instanceMethod, Class<?> functionalIntfCls) {
    try {
      Lookup lookup = LOOKUP.in(instanceMethod.getDeclaringClass());
      allowedModesField.set(lookup, ALL_MODES);

      Method intfMethod = findAbstractMethod(functionalIntfCls);
      MethodHandle methodHandle = lookup.unreflect(instanceMethod);

      MethodType intfMethodType = MethodType.methodType(intfMethod.getReturnType(), intfMethod.getParameterTypes());
      MethodType instanceMethodType = MethodType
          .methodType(instanceMethod.getReturnType(), instanceMethod.getParameterTypes());
      CallSite callSite = LambdaMetafactory.metafactory(
          lookup,
          intfMethod.getName(),
          MethodType.methodType(functionalIntfCls, instance.getClass()),
          intfMethodType,
          methodHandle,
          instanceMethodType);

      return (T) callSite.getTarget().bindTo(instance).invoke();
    } catch (Throwable e) {
      throw new IllegalStateException("Failed to create lambda from " + instanceMethod, e);
    }
  }

  // instanceMethod对应的方法为public void org.apache.servicecomb.core.definition.OperationConfig.setSlowInvocationEnabled(boolean)
  // invokedynamic 是 Java 7 引入的一条新指令,用以支持动态语言的方法调用。具体来说,它将调用点(CallSite)抽象成一个 Java 类,并且将原本由 Java 虚拟机控制的方法调用以及方法链接暴露给了应用程序。在运行过程中,每一条 invokedynamic 指令将**一个调用点,并且会调用该调用点所链接的方法句柄。
  // createLambda实现将目标方法包装为对应的接口方法的功能
  @SuppressWarnings("unchecked")
  public static <T> T createLambda(Method instanceMethod, Class<?> functionalIntfCls) {
    try {
	  // 找到对应的Lookup对象,设置可以访问所有的字段
      Lookup lookup = LOOKUP.in(instanceMethod.getDeclaringClass());
      allowedModesField.set(lookup, ALL_MODES);

	  // 找到functionalIntfCls中对应的set方法
      Method intfMethod = findAbstractMethod(functionalIntfCls);
	  // 使用MethodHandlers.Lookup.unreflect可以构建对应方法的代理
      MethodHandle methodHandle = lookup.unreflect(instanceMethod);
      // java.lang.invoke中的MethodType封装了方法的参数
	  // intfMethodType的值为(Object,Object)void,
      MethodType intfMethodType = MethodType.methodType(intfMethod.getReturnType(), intfMethod.getParameterTypes());
      // instanceMethodType的值为(OperationConfig,boolean)void
	  MethodType instanceMethodType = methodHandle.type();
	  // lookup对应instanceMethod的声明类信息
	  // intfMethod.getName()为接口方法的名称,如果为IntGetter接口,对应的名称为get
	  // MethodType.methodType(functionalIntfCls) 期望的方法的调用类型
	  // intfMethodType需要实现的方法的入参和出参的类型信息
	  // methodHandle需要实现的方法
	  // instanceMethodType需要实现的方法的参数信息
      CallSite callSite = LambdaMetafactory.metafactory(
          lookup,
          intfMethod.getName(),
          MethodType.methodType(functionalIntfCls),
          intfMethodType,
          methodHandle,
          instanceMethodType);
      // 通过CallSite新建对应的functionalIntfCls对象
      return (T) callSite.getTarget().invoke();
    } catch (Throwable e) {
      throw new IllegalStateException("Failed to create lambda from " + instanceMethod, e);
    }
  }

  public static <T> T createGetter(Method getMethod) {
    // 查询本地缓存中是否存在该方法对应的信息
    Class<?> getterCls = GETTER_MAP.getOrDefault(getMethod.getReturnType(), Getter.class);
	// getterCls对应的为interface org.apache.servicecomb.foundation.common.utils.bean.IntGetter对象
    return createLambda(getMethod, getterCls);
  }

  // slower than reflect directly
  @SuppressWarnings("unchecked")
  public static <C, F> Getter<C, F> createGetter(Field field) {
    field.setAccessible(true);
    return instance -> {
      try {
        return (F) field.get(instance);
      } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
      }
    };
  }

  public static <T> T createSetter(Method setMethod) throws Throwable {
    Class<?> setterCls = SETTER_MAP.getOrDefault(setMethod.getParameterTypes()[0], Setter.class);
    return createLambda(setMethod, setterCls);
  }

  // slower than reflect directly
  // 如果字段没有对应的setter方法,通过反射设置字段是可访问的,并返回设置字段的方法
  public static <C, F> Setter<C, F> createSetter(Field field) {
    field.setAccessible(true);
    return (instance, value) -> {
      try {
        field.set(instance, value);
      } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
      }
    };
  }
}

此处以单元测试用例方法,分析接口方法的代理新建的逻辑:

@Test
  public void createGetterSetterByMethod() throws Throwable {
    // Model.class.getMethod("getF1")新建对应的getF1对应的Method
    IntGetter<Model> getter = LambdaMetafactoryUtils.createGetter(Model.class.getMethod("getF1"));
    IntSetter<Model> setter = LambdaMetafactoryUtils.createSetter(Model.class.getMethod("setF1", int.class));
    BiFunction<Object, Object, Object> echo = LambdaMetafactoryUtils
        .createLambda(Model.class.getMethod("echo", List.class), BiFunction.class);

    setter.set(model, 1);
    int f1 = getter.get(model);
    Assert.assertEquals(1, f1);
    Assert.assertThat((List<Integer>) echo.apply(model, Arrays.asList(2)), Matchers.contains(2));
  }

org.apache.servicecomb.config.inject.PlaceholderResolver实现了解析占位符参数的功能:

/**
 * <pre>
 * not care for performance
 *
 * behavior of multiple list if defined:
 *   org.apache.servicecomb.config.inject.TestPlaceholderResolver#multi_list()
 * behavior of nested and multiple list variable is undefined
 *   org.apache.servicecomb.config.inject.TestPlaceholderResolver#mixed()
 * </pre>
 */
public class PlaceholderResolver {
  private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("(?<escape>\\\\)?\\$\\{(?<name>[^{}]+)\\}");

  // 静态内部类,存储输入字符串的每段的解析结果
  static class SplitPart {
    // 是否是变量标记
    boolean var;
    // 全名称
    String fullName;
    // 对应的值
    Object value;

    public SplitPart(boolean var, String fullName) {
      this.var = var;
      this.fullName = fullName;
    }

    @Override
    public String toString() {
      return "SplitPart{" +
          "var=" + var +
          ", fullName='" + fullName + '\'' +
          ", value=" + value +
          '}';
    }
  }

  // 静态内部类,封装最终的key的解析结果
  static class Row {
    List<SplitPart> parts = new ArrayList<>();

    int cartesianProductCount = 1;

    int varCount = 0;
  }

  // 例如 str为prefix.${key}.suffix
  // parameters为 
  // parameters.put("key", "value");
  // parameters.put("varOfVar", Arrays.asList("${key}"));
  // parameters.put("priority", "low");
  // parameters.put("low-list", Arrays.asList("low-1", "low-2"));
  // parameters.put("middle-list", Arrays.asList("middle-1", "middle-2"));
  // parameters.put("high-list", Arrays.asList("high-1", "high-2"));
  public List<String> replace(String str, Map<String, Object> parameters) {
    // 获取到最值的解析结果,其中每个结果中,varCount均为0
    List<Row> finalRows = replaceToRows(str, parameters);

    List<String> replaced = new ArrayList<>();
    for (Row row : finalRows) {
	  // 从finalRows中获取对应的结果,存入replaced中
      resolve(row, replaced);
    }

    for (int idx = 0; idx < replaced.size(); idx++) {
      String row = replaced.get(idx);
	  // 过滤其中包含的\\$替换为$符号
      replaced.set(idx, row.replace("\\$", "$"));
    }
    return replaced;
  }

  private List<Row> replaceToRows(String str, Map<String, Object> parameters) {
    List<Row> finalRows = new ArrayList<>();
    List<String> remainRows = new ArrayList<>();
    // finalRows为最终的解析结果,remainRows对应解析的中间结果
	replaceToRows(str, parameters, remainRows, finalRows);

    for (String row : remainRows) {
	  // 递归调用replaceToRows,获取最终的解析结果
      List<Row> nestedRows = replaceToRows(row, parameters);
      finalRows.addAll(nestedRows);
    }
    return finalRows;
  }

  private void replaceToRows(String str, Map<String, Object> parameters, List<String> remainRows,
      List<Row> finalRows) {
	// 将key解析为对应的Row对象
    Row row = parseToRow(str, parameters);
    if (row.varCount == 0 && row.cartesianProductCount == 1) {
      finalRows.add(row);
      return;
    }
    // 获取对应的解析结果
    resolve(row, remainRows);
  }

  // str对应的是prefix.${key}.suffix
  private Row parseToRow(String str, Map<String, Object> parameters) {
    Matcher matcher = PLACEHOLDER_PATTERN.matcher(str);
    Row row = new Row();

    int last = 0;
	// 使用正则表达式对待匹配对象进行一一匹配,寻找其中的${}占位符
    while (matcher.find()) {
      row.parts.add(new SplitPart(false, str.substring(last, matcher.start())));
      last = matcher.end();

      if (matcher.group("escape") != null) {
	    // 构建对应的SplitPart对象,找到escape的匹配对象
        row.parts.add(new SplitPart(false, matcher.group().substring(1)));
        continue;
      }
      // 找到name的匹配对象,对应值为key
      String name = matcher.group("name");

      Object value = findValue(parameters, name);
      if (value instanceof Collection) {
	    // 如果解析的参数是List,则存在笛卡尔积的问题,会解析出多种结果出来
        row.cartesianProductCount *= ((Collection) value).size();
      }
      if (value != null) {
        row.varCount++;
      }
      // 将匹配结果封装为SplitPart对象
      SplitPart splitPart = new SplitPart(value != null, matcher.group());
      splitPart.value = value;
	  // 
      row.parts.add(splitPart);
    }
    row.parts.add(new SplitPart(false, str.substring(last)));

    return row;
  }

  // resolve placeholder and execute cartesian product
  // row为对应的key的解析结果
  @SuppressWarnings("unchecked")
  private void resolve(Row row, List<String> resolvedRows) {
    // 笛卡尔积
	List<StringBuilder> stringBuilders = new ArrayList<>();
    for (int idx = 0; idx < row.cartesianProductCount; idx++) {
      stringBuilders.add(new StringBuilder());
    }

    int collectionRepeatCount = 1;
	// 对于key的解析出来的每一部分,组合为最终的结果
    for (SplitPart part : row.parts) {
      if (!part.var) {
        for (int idx = 0; idx < row.cartesianProductCount; idx++) {
          StringBuilder sb = stringBuilders.get(idx);

          if (part.fullName.startsWith("$")) {
            sb.append("\\" + part.fullName);
            continue;
          }

          sb.append(part.fullName);
        }
        continue;
      }

      if (part.value instanceof Collection) {
        int size = ((Collection<String>) part.value).size();
        int rowRepeatCount = row.cartesianProductCount / size / collectionRepeatCount;

        int valueIdx = 0;
        for (int collectionRepeatIdx = 0; collectionRepeatIdx < collectionRepeatCount; collectionRepeatIdx++) {
          for (String value : (Collection<String>) part.value) {
            for (int repeatIdx = 0; repeatIdx < rowRepeatCount; repeatIdx++) {
              StringBuilder sb = stringBuilders.get(valueIdx);
              valueIdx++;
              sb.append(value);
            }
          }
        }

        collectionRepeatCount *= size;
        continue;
      }

      // normal var
      for (int idx = 0; idx < row.cartesianProductCount; idx++) {
        StringBuilder sb = stringBuilders.get(idx);
        sb.append(part.value);
      }
    }

    for (StringBuilder sb : stringBuilders) {
      resolvedRows.add(sb.toString());
    }
  }

  private Object findValue(Map<String, Object> parameters, String key) {
    Object value = parameters.get(key);
    if (value == null) {
	  // 如果传入的parameters找不到,通过ConfigUtil进行寻找
      value = ConfigUtil.getProperty(key);
    }
    return value;
  }
}

org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils的修改对应的this.config = SCBEngine.getInstance().getPriorityPropertyManager().createConfigObject设置的配置项的值:

public static void setProperty(String key, Object value) {
    // ensure have instance
    DynamicPropertyFactory.getInstance();
    // 获取到对应的配置
    ConcurrentCompositeConfiguration config = (ConcurrentCompositeConfiguration) DynamicPropertyFactory
        .getBackingConfigurationSource();
    if (value != null) {
	  // 选择一个数据源,将对应的值设置进入其中即可
      config.getConfiguration(0).setProperty(key, value);
      return;
    }

    config.getConfiguration(0).clearProperty(key);
  }

NUWA的自定义配置加载逻辑

nuwa使用com.huawei.nuwa.config.ConfigurationService实现了自定义配置的加载逻辑:

public class ConfigurationService extends PropertyPlaceholderConfigurer implements DisposableBean {
    private static final int NORMAL_FILE_COUNT = 2;

    private static final int ORDER = Ordered.LOWEST_PRECEDENCE / 2 - 100;

    private static final ConfigurationService INSTANCE = new ConfigurationService();

    /**
     * Gets instance.
     *
     * @return the instance
     */
    public static ConfigurationService getInstance() {
        return INSTANCE;
    }

    private final ConcurrentCompositeConfiguration compositeConfiguration;

    private final ConvertableConfiguration convertableConfiguration;

    private final TreeSet<ConfigurationLoader> configurationLoaders;

    private ScheduledExecutorService scheduler;

    private ConfigurationService() {
        // !!保证比CSE的org.apache.servicecomb.config.ConfigurationSpringInitializer晚加载!!
        setOrder(ORDER);
		// 对于无法解析的占位符和无法发现的文件不报错
        setIgnoreUnresolvablePlaceholders(true);
        setIgnoreResourceNotFound(true);
		// 去除配置值前后的空格
        setTrimValues(true);
        // 获取配置管理对象
        compositeConfiguration = new ConcurrentCompositeConfiguration();
		// 不使用分割符将string配置分割为list
        compositeConfiguration.setDelimiterParsingDisabled(true);
        // ConvertableConfiguration是对ConcurrentCompositeConfiguration的封装
        convertableConfiguration = new ConvertableConfiguration(compositeConfiguration);
        convertableConfiguration.setDelimiterParsingDisabled(true);
        // nuwa提供了一个配置的加载扩展,通过SPI模式加载对应的实现类,对应的接口为ConfigurationLoader
		// NuwaFactoriesLoader.loadFactories实现了对应的自定义配置类的加载功能
        configurationLoaders = Sets.newTreeSet(
            NuwaFactoriesLoader.loadFactories(ConfigurationLoader.class, ConfigurationService.class.getClassLoader(),
                true));
	    // scheduler实现对于配置项的定时刷新功能
        scheduler = Executors.newScheduledThreadPool(NORMAL_FILE_COUNT,
            new ThreadFactoryBuilder().setDaemon(true).setNameFormat("nuwa-monitor-file-%d").build());
        this.compositeConfiguration.addConfiguration(InnerDefaultConfigurationHolder.getInstance().getConfiguration(),
            "NuwaInnerDefault");
    }

    /**
     * 初始化converters
     * 在塞给com.netflix.config的时候要初始化先
     *
     * @see DynamicPropertyRegistry#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory)
     */
    public void initPropertyConverters() {
        Properties properties = new Properties();
        Iterator<String> iter = compositeConfiguration.getKeys();
        while (iter.hasNext()) {
            String key = iter.next();
            Object value = compositeConfiguration.getProperty(key);
            properties.setProperty(key, value.toString());
        }

        PropertyConverters converters = PropertyConverters.getInstance();
        converters.init(properties);
    }

    /**
     * Merge properties properties.
     *
     * @return the properties
     * @throws IOException the io exception
     */
    @Override
    protected Properties mergeProperties() throws IOException {
        Properties properties = super.mergeProperties();
        Iterator<String> iter = compositeConfiguration.getKeys();
        while (iter.hasNext()) {
            String key = iter.next();
            Object value = compositeConfiguration.getProperty(key);
            properties.setProperty(key, value.toString());
        }
        PropertyConverters converters = PropertyConverters.getInstance();
        Properties newProperties = new Properties(properties);
        properties.forEach((key1, oldValue) -> {
            String key = (String) key1;
            Object newValue = converters.convert(key, oldValue);

            newProperties.put(key, newValue);
        });
        return newProperties;
    }

    /**
     * Gets convertable configuration.
     *
     * @return the convertable configuration
     */
    public ConcurrentCompositeConfiguration getConvertableConfiguration() {
        return convertableConfiguration;
    }

    /**
     * Gets configuration.
     *
     * @return the configuration
     */
    public ConcurrentCompositeConfiguration getConfiguration() {
        return compositeConfiguration;
    }

    /**
     * Add configuration.
     *
     * @param configuration the configuration
     */
    public void addConfiguration(AbstractConfiguration configuration) {
        this.compositeConfiguration.addConfigurationAtFront(configuration, null);
    }

    /**
     * Add configuration url.
     *
     * @param cfgURL the cfg url
     */
    public void addConfigurationUrl(URL cfgURL) {
        addConfiguration(createDynamicConfiguration(cfgURL));
    }

    private DynamicConfiguration createDynamicConfiguration(URL cfgURL) {
        return createDynamicConfiguration(cfgURL, new FixedRatePollingScheduler(scheduler));
    }

    private DynamicConfiguration createDynamicConfiguration(URL cfgURL, AbstractPollingScheduler scheduler) {
        Configuration configuration = createConfiguration(cfgURL);
        DynamicConfiguration dynamicConfiguration = new DynamicConfiguration();
        dynamicConfiguration.setDelimiterParsingDisabled(true); //
        dynamicConfiguration.startPolling(new DelegatedConfigurationSource(configuration), scheduler);
        return dynamicConfiguration;
    }

    private AbstractConfiguration createConfiguration(URL cfgURL) {
        for (ConfigurationLoader loader : configurationLoaders) {
            if (loader.accept(cfgURL)) {
                try {
                    AbstractConfiguration configuration = loader.loadConfiguration(cfgURL);
                    if (configuration != null) {
                        return configuration;
                    }
                } catch (ConfigurationException e) {
                    throw new IllegalArgumentException("cannot resolve the config file :" + cfgURL, e);
                }
            }
        }
        throw new IllegalArgumentException("no configuration loader to process the config file :" + cfgURL);
    }

    /**
     * Destroy.
     */
    @Override
    public void destroy() {
        if (scheduler != null) {
            scheduler.shutdown();
        }
    }

    private static class ConvertableConfiguration extends ConcurrentCompositeConfiguration {
        /**
         * Instantiates a new Convertable configuration.
         *
         * @param delegated the delegated
         */
        public ConvertableConfiguration(AbstractConfiguration delegated) {
            super();
            addConfiguration(delegated);
        }

        /**
         * Gets property.
         *
         * @param s the s
         * @return the property
         */
        @Override
        public Object getProperty(String s) {
		    // 此处会进行一些解密操作
            return PropertyConverters.getInstance().convert(s, super.getProperty(s));
        }

        /**
         * Get string array string [ ].
         *
         * @param key the key
         * @return the string [ ]
         */
        public String[] getStringArray(String key) {
            String[] tokens = super.getStringArray(key);
            if (tokens != null && tokens.length > 0) {
                return Arrays.stream(tokens)
                    .map(s -> PropertyConverters.getInstance().convert(key, s))
                    .toArray(String[]::new);
            }
            return tokens;
        }

        @Override
        public void addConfigurationListener(ConfigurationListener listener) {
            super.addConfigurationListener(event -> listener.configurationChanged(
                new ConfigurationEvent(event.getSource(), event.getType(), event.getPropertyName(),
                    PropertyConverters.getInstance().convert(event.getPropertyName(), event.getPropertyValue()),
                    event.isBeforeUpdate())));
        }
    }
}

com.huawei.nuwa.ConfigInitializer实现了加载指定配置路径下的配置的功能:

/**
 * 加载机器主机信息
 * 加载classpath下配置文件
 * 解决SDS\DCS的DC名称
 *
 * @author z00249298
 * @since 2019-09-16
 */
class ConfigInitializer {
    // 加载的配置项的路径
    private static final String[] CONFIG_LOCATIONS = SystemHelper.getArrayProperty("nuwa.system.configLocations", ",",
        new String[] {"classpath*:*config.properties", "classpath*:*config.yaml"});

    private ConfigInitializer() {
    }

    /**
     * Init.
     */
    static void init() {
        StartupInfoLogger.getLogger().info("Loaded configuration files from " + Arrays.toString(CONFIG_LOCATIONS));

        // 加载类路径下的配置文件
        loadClassPathConfig();
    }

    private static void loadClassPathConfig() {
        if (ArrayUtils.isNotEmpty(CONFIG_LOCATIONS)) {
            ConfigurationService configurationService = ConfigurationService.getInstance();
			// 逐一加载对应配置路径下的配置文件的信息
            for (String location : CONFIG_LOCATIONS) {
                try {
				    // 通过 ResourceLoader获取对应的配置项的坐标
                    Resource[] resources = ResourceLoader.getResource(ConfigInitializer.class.getClassLoader(),
                        location);
                    if (ArrayUtils.isNotEmpty(resources)) {
                        for (Resource resource : resources) {
                            if (Optional.ofNullable(resource)
                                .map(Resource::getFilename)
                                .map(fileName -> fileName.startsWith("."))
                                .orElse(false)) {
                                continue;
                            }
							// 对于获取到的所有配置文件加载到ConfigurationService中
                            configurationService.addConfigurationUrl(resource.getURL());
                            StartupInfoLogger.getLogger().info("Loaded configuration file url: " + resource.getURL());
                        }
                    }
                } catch (IOException e) {
                    throw new NuwaRuntimeException("failed to load config resource", e);
                }
            }
        }
    }
}

Webplatform的配置加载逻辑

com.huawei.webplatform.propertyconfig.ConfigurationService类继承了PropertyPlaceholderConfigurer实现自定义的加载类:

webplatform配置加载类比nuwa的配置加载类后加载,通过init方法,将自定义的配置文件信息加载到archaius配置管理类中。

@Order(Integer.MIN_VALUE)
public class ConfigurationService extends PropertyPlaceholderConfigurer {
...

    /**
     * 初始化
     */
    public void init() {
        LOGGER.info("init {}", webplatformLocations.length);
        if (ArrayUtils.isNotEmpty(webplatformLocations)) {
            for (Resource resource : webplatformLocations) {
                try {
                    addConfigurationUrl(resource.getURL());
                } catch (IOException e) {
                    throw new ComRuntimeException("failed to load config resource", e);
                }
            }
        }
    }

...

}

总结

(1)ConfigurationSpringInitializer实现了配置文件的加载 (2)InjectProperty和InjectProperties实现了自定义配置的加载和更新能力