Apollo接入配置中心 -- 源码分析之如何获取配置

全文参考:https://mp.weixin.qq.com/s/G5BV5BIdOtB3LlxNsr4ZDQ

https://blog.csdn.net/crystonesc/article/details/106630412

https://www.cnblogs.com/deepSleeping/p/14565774.html

背景:近期在接入行内配置中心,因此对配置的加载接入有了一些兴趣,由于当时接入Apollo配置中心出现过不少问题,所以做以下整理。

此处参考:https://blog.csdn.net/crystonesc/article/details/106630412

​ 使用Apollo接入,但由于是SpringMVC项目,且原先部分配置与Apollo加载存在冲突,无法使用SpringBean方式管理接入配置。因此使用Apollo中获取的配置方式接入。具体代码如下:

Config config = ConfigService.getConfig("application.properties"); 
String userNmae = config.getProperty("st.username", null);
  1. 此处 ConfigService.getConfig() 传入的是namespace,在Apollo配置中心默认是 application.properties
  2. getConfig()追溯到最终的实现类,通过namespaces。

ConfigService.getConfig()方法是在ConfigService类中的,ConfigService是一个单例,也就是说对于应用程序来说只会有一个ConfigService的实例,并且实例是被通过私有静态变量被持有在ConfigService当中。

private static final ConfigService s_instance = new ConfigService();

​ 同时我们看到ConfigService持有两个属性ConfigManager和ConfigRegistry,其中ConfigManager是配置(ConfigManager)的管理器,ConfigRegistry用于手工配置注入,这两个属性的初始化均是通过ApolloInjector来注入的。ConfigService中的另外一个方法getAppConfig,该方法用户获取application配置文件的内容(apollo中创建的默认配置文件(namespace))。而getAppConfig中会实际调用getConfig获取配置,getConfig则是通过ConfigManager去获取配置。

// 通过namespace获取Config,首先从m_configs缓存中获取,
// 如果没有获取则通过ConfigFacotryManager获取ConfigFactory并创建Config
public Config getConfig(String namespace) {
    Config config = m_configs.get(namespace);
    if (config == null) {
        synchronized (this) {
    	    config = m_configs.get(namespace);
            if (config == null) {
    	        ConfigFactory factory = m_factoryManager.getFactory(namespace);
    	        config = factory.create(namespace);
    	        m_configs.put(namespace, config);
    	    }
       }
   }
    return config;
}

​ 源码中,关于配置的获取,可以追溯到config = factory.create(namespace);

ConfigFactory factory = m_factoryManager.getFactory(namespace);
config = factory.create(namespace);
m_configs.put(namespace, config);

​ 也就是说,在此完成了配置的创建和获取。

public Config create(String namespace) {
    // 判断namespace的文件类型
    ConfigFileFormat format = this.determineFileFormat(namespace);
    ConfigRepository configRepository = null;
    // 判断文件属性是否不为 properties,需要注意 format !=
    if (ConfigFileFormat.isPropertiesCompatible(format) && format != ConfigFileFormat.Properties) {
        configRepository = this.createPropertiesCompatibleFileConfigRepository(namespace, format);
    } else {
        // application.properties 会走到这个方法
        configRepository = this.createConfigRepository(namespace);
    }
    logger.debug("Created a configuration repository of type [{}] for namespace [{}]", configRepository.getClass().getName(), namespace);
    return this.createRepositoryConfig(namespace, (ConfigRepository)configRepository);
}

​ 在 configRepository = this.createConfigRepository(namespace); 方法中,实际上会去访问 本地持久化的 apollo 配置,默认地址为 /opt/data。

注:以下代码之间非一个类中,为方便关联查看进行了位置调整。

LocalFileConfigRepository createLocalConfigRepository(String namespace) {
    if (this.m_configUtil.isInLocalMode()) {
        logger.warn("==== Apollo is in local mode! Won't pull configs from remote server for namespace {} ! ====", namespace);
        return new LocalFileConfigRepository(namespace);
    } else {
        // 此处往下调用
        return new LocalFileConfigRepository(namespace, this.createRemoteConfigRepository(namespace));
    }
}

public LocalFileConfigRepository(String namespace, ConfigRepository upstream) {
    this.m_sourceType = ConfigSourceType.LOCAL;
    this.m_namespace = namespace;
    this.m_configUtil = (ConfigUtil)ApolloInjector.getInstance(ConfigUtil.class);
    // 此处往下调用
    this.setLocalCacheDir(this.findLocalCacheDir(), false);
    this.setUpstreamRepository(upstream);
    this.trySync();
}

private File findLocalCacheDir() {
    try {
        // 此处往下调用
        String defaultCacheDir = this.m_configUtil.getDefaultLocalCacheDir();
        Path path = Paths.get(defaultCacheDir);
        if (!Files.exists(path, new LinkOption[0])) {
            Files.createDirectories(path);
        }
        if (Files.exists(path, new LinkOption[0]) && Files.isWritable(path)) {
            return new File(defaultCacheDir, "/config-cache");
        }
    } catch (Throwable var3) {
    }
    return new File(ClassLoaderUtil.getClassPath(), "/config-cache");
}

public String getDefaultLocalCacheDir() {
    String cacheRoot = this.getCustomizedCacheRoot();
    if (!Strings.isNullOrEmpty(cacheRoot)) {
        return cacheRoot + File.separator + this.getAppId();
    } else {
        // 此处可以看到会去默认的 /opt/data/ 寻找缓存apollo配置中心的应用配置
        cacheRoot = this.isOSWindows() ? "C:\\opt\\data\\%s" : "/opt/data/%s";
        return String.format(cacheRoot, this.getAppId());
    }
}

​ 在回到 create()方法 返回值为return this.createRepositoryConfig(namespace, (ConfigRepository)configRepository);,定睛一看,实际上最后返回了DefaultConfig。

protected Config createRepositoryConfig(String namespace, ConfigRepository configRepository) {
    return new DefaultConfig(namespace, configRepository);
}
return new DefaultConfig(namespace, configRepository);

​ 而DefaultConfig的构造方法中 this.loadFromResource(this.m_namespace); 完成了配置的读取。

public DefaultConfig(String namespace, ConfigRepository configRepository) {
    this.m_sourceType = ConfigSourceType.NONE;
    this.m_namespace = namespace;
    this.m_resourceProperties = this.loadFromResource(this.m_namespace);
    this.m_configRepository = configRepository;
    this.m_configProperties = new AtomicReference();
    this.m_warnLogRateLimiter = RateLimiter.create(0.017);
    this.initialize();
}

在 loadFromResource(this.m_namespace); 中,取到了在 META-INF/config/ 下的为 namespace 的配置。

private Properties loadFromResource(String namespace) {
    String name = String.format("META-INF/config/%s.properties", namespace);
    InputStream in = ClassLoaderUtil.getLoader().getResourceAsStream(name);
    Properties properties = null;
    if (in != null) {
        properties = this.propertiesFactory.getPropertiesInstance();
        try {
            properties.load(in);
        } catch (IOException var14) {
            Tracer.logError(var14);
            logger.error("Load resource config for namespace {} failed", namespace, var14);
        } finally {
            try {
                in.close();
            } catch (IOException var13) {
            }
        }
    }
    return properties;
}

至此配置完成了获取。配置如何刷新、拉取,有时间会再次进行更新,还请各位看官耐心等待。

小结: img

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要编译和搭建Apollo配置中心源码,您可以按照以下步骤进行: 1. 下载源码:访问Apollo的官方GitHub仓库(https://github.com/ctripcorp/apollo),找到并下载源码包。 2. 配置数据库:Apollo使用MySQL作为配置存储的数据库,您需要安装并配置MySQL数据库,并创建一个用于存储Apollo配置的数据库。 3. 导入数据库脚本:在Apollo源码的scripts目录中,有一个createTable.sql文件,您需要先创建该数据库中的表结构,可以使用命令行或可视化工具导入该脚本。 4. 修改数据库连接配置:在Apollo源码apollo-configservice子项目中,找到src/main/resources/application-github.properties文件,将文件中的数据库连接配置修改为您自己的配置。 5. 编译源码:进入到Apollo源码的根目录,执行mvn clean package命令进行编译,这将生成一个target目录,其中包含了编译后的可执行文件。 6. 部署和运行:将编译后的target目录中的可执行文件部署到您的服务器上,执行启动脚本即可启动Apollo配置中心。您可以根据需要,修改可执行文件中的配置参数来适应您的环境需求。 在搭建Apollo配置中心之前,您还需要确保服务器上已经安装了Java环境和Maven构建工具。此外,Apollo还涉及到其他组件和依赖,需要您按照文档中的说明进行安装和配置。 运行成功后,您可以通过访问配置中心的页面,进行应用创建、配置管理和发布等操作。同时,Apollo还提供了丰富的扩展接口和功能,可以满足不同场景的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值