zoukankan      html  css  js  c++  java
  • 携程apollo系列-客户端集成

    本文讲解如何在 Java 程序中集成 Apollo 配置, 主要涉及到一些基础用法.
    对于一些高级用法, 比如如何加密/解密配置项 (可用于数据库密码配置), 如何动态切换数据源地址,如何动态切换日志级别,

    可以参考官方的 user cases git 库, 官方代码库 https://github.com/ctripcorp/apollo-use-cases 和 InfoQ 微信文章: GitHub 9K Star!Apollo作者手把手教你微服务配置中心之道 

    在开始集成之前, 先了解一些 apollo 相关概念.

    ================================================
    基本概念
    ================================================
    Apollo 几个术语的从属关系: 环境>项目>集群>命名空间.

    1. 集群概念
    这里的集群不是指 apollo 配置中心集群, 而是指受管项目的集群. 另外需要区分集群和环境术语的差异, 这里的集群相当于数据中心 (idc) 的概念, 比如一个大型系统的生产环境, 可能会部署在多个不同的数据中心.
    一个应用可以包含多个集群, 缺省的集群名为"default", 比如在不同机房, 项目使用到 redis 地址不同. 如果不同 idc 使用同样的配置, 则没有必要创建集群. 对于一般项目而言都是部署在同一个数据中心中, 没有必要专门新加集群.
    如果在 apollo 中为某个应用配置了集群, 需要在应用的文件系统中, 告知所在集群的名字, 方法是:
    在 /opt/settings/server.properties(linux) 文件 或 C:optsettingsserver.properties(windows) 文件中, 设定 idc 属性值为集群名称.


    2. Namespace 概念:
    namespace 可以认为是配置项的一个容器, 类似于配置文件的概念.
    namespace 的作用:
    (1). 作为配置项的一个容器
    (2). 用于细化权限管控, 比如某个命名空间只允许 DBA 修改和发布, 另一个只允许运维修改和发布.
    (3). 用于配置项版本整体回滚
    一个应用可以包含多个 namespace, 缺省的 namespace 名为 "application".
    添加 namespace 需要指定配置文件格式, 支持 properties/xml/json/yaml 等格式, 缺省的格式为 properties.
    正常情况下一个 namespace 应该是从属于某个应用, 但也可以构建多个应用公用的的 namespace.

    对于一个应用而言, namespace 建议分为业务配置和系统配置两类.
    (1)业务配置 namespace: 和业务相关的配置.
    (2)系统配置 namespace: 包含数据库地址/账号等信息.


    3. 环境
    apollo 的环境术语和我们平时所讲的环境含义一致, 比如开发/生产环境. apollo 后台的 apolloconfigdb 表仅支持一个环境, 如果要支持多个环境, 必须有多个 MySQL 服务器和多个 config service, 但 apollo portal 是支持多环境集中管理.
    apollo 支持 DEV/UAT/PRO/FAT 等环境名称, 大小写不敏感, 还有一个特别的 Local 环境名, 代表程序时仅读取本地缓存目录下的配置文件.

    支持的环境名有:
    DEV -- dev 环境
    FAT -- feature Acceptance test
    UAT -- user Acceptance test
    PRO -- production 环境
    Local -- 读取本地缓存目录下的配置文件

    设置 env=Local, 程序仅读本地缓存目录下的配置文件, 下面是缺省的本地缓存路径, 可以通过 apollo.cacheDir 参数来调整缺省的缓存路径
    ## Mac/Linux: /opt/data/{appId}/config-cache
    ## Windows: C:optdata{appId}config-cache
    具体的缓存文件名为: {appId}+{cluster}+{namespace}.properties


    ================================================
    pom.xml
    ================================================

    增加 apollo-client 依赖.

    <dependency>
        <groupId>com.ctrip.framework.apollo</groupId>
        <artifactId>apollo-client</artifactId>
        <version>1.1.0</version>
    </dependency>

    ================================================
    设定远程 Apollo 服务器连接信息
    ================================================
    Apollo 提供很多方式来设定远程配置服务, 下面仅仅列出其中一些方式.
    接入Apollo的 SpringBoot 程序, 推荐使用 System property 配置 apollo 参数,  application.properties不要再配加任何参数, 仅仅保留一个空文件, 其他参数都配在 apollo 中, 当然我们不能把apollo服务器连接参数配到apollo中. 

    另外, 一旦接入了 apollo 系统, 如果 application.properties 和 apollo 中有同名的参数, 以apollo中的配置为准. 

    方式 1: 通过 System property 形式, 比如命令行增加参数:
    System property 支持所有的参数, 黑体字为最重要的参数, 推荐在启动命令行中设定. 
    -Dapp.id=YOUR-APP-ID
    -Dapollo.meta=http://config-service-url
    -Denv=DEV
    -Dapollo.cacheDir=/opt/data/some-cache-dir
    -Dapollo.cluster=SomeCluster

    对于 meta server, 也可以 -D{env}.meta 这样的形式指定.


    方式 2: 通过 SpringBoot 的 application.properties 文件指定
    application.properties 中除了不能指定 env 参数外, 其他都参数都支持.
    app.id=YOUR-APP-ID
    apollo.meta=http://localhost:8080
    apollo.cacheDir=/opt/data/some-cache-dir
    apollo.cluster=SomeCluster
    apollo.bootstrap.enabled = true
    apollo.bootstrap.namespaces = application,other_namespace
    apollo.autoUpdateInjectedSpringProperties=true # 自动更新 @Value 注解的属性


    方式 3: 通过 META-INF/app.properties 文件设定
    只能用来设置 app.id 和 apollo.meta 参数.
    app.properties 文件的位置是: classpath:/META-INF/app.properties
    app.id=YOUR-APP-ID
    apollo.meta=http://localhost:8080


    方式 4: 通过 server.properties 配置文件
    不能用来设定 app.id 参数, 主要用来设定这台服务器上的通用设置, 比如 meta 和 cluster 和 cacheDir 等参数, 其中 idc 参数等同于 apollo.cluster 参数.
    对于 Mac/Linux, 文件位置为/opt/settings/server.properties
    对于 Windows, 文件位置为 C:optsettingsserver.properties
    env=DEV
    idc=SomeCluster
    apollo.meta=http://config-service-url
    apollo.cacheDir=/opt/data/some-cache-dir
    dev.meta=http://localhost:8080
    fat.meta=http://apollo.fat.xxx.com
    uat.meta=http://apollo.uat.xxx.com
    pro.meta=http://apollo.xxx.com


    方式 5: 通过 apollo-env.properties 设置各环境的服务器地址
    主要用来指定 meta server 的地址. apollo-env.properties 文件位置是 resources 目录下
    dev.meta=http://localhost:8080
    fat.meta=http://apollo.fat.xxx.com
    uat.meta=http://apollo.uat.xxx.com
    pro.meta=http://apollo.xxx.com


    ================================================
    Spring 项目和 apollo 集成方式
    ================================================
    Java项目要集成Apollo 有很多种方式, 下面是常用方式:
    方式 1: 使用 Java API 方式, 不仅适合 Spring 项目, 而且适合非 Spring 项目, 灵活方便, 支持热部署.
    方式 2: Spring 的 @Value 方式关联 appollo 配置项. 该方式使用简单, 但可控性较差.
    方式 3: 结合 SpringBoot 的 @ConfigurationProperties 注解. 该方法使用稍微复杂, 但可控性好.
    方式 4. 使用 Apollo 的 @ApolloConfig 和 @ApolloConfigChangeListener .
    方式 5. Spring 项目通过 Environment, 该方式使用较为麻烦, 推荐使用方式 2 或 3.


    ----------------------------------------
    方式 1: 使用 Java API 方式
    ----------------------------------------

    // 从缺省的获取 application 命名空间 
    Config config = ConfigService.getAppConfig(); 
    //获取其他 namespace 的配置
    //Config config = ConfigService.getConfig(String namespace, ConfigFileFormat configFileFormat); 
    String someKey = "someKeyFromDefaultNamespace";
    String someDefaultValue = "someDefaultValueForTheKey";
    String value = config.getProperty(someKey, someDefaultValue);
    
    // 增加监听事件
    config.addChangeListener(new ConfigChangeListener() {
        @Override
        public void onChange(ConfigChangeEvent changeEvent) {
            for (String key : changeEvent.changedKeys()) {
                ConfigChange change = changeEvent.getChange(key);
                System.out.println(String.format("Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s", change.getPropertyName(),
                        change.getOldValue(), change.getNewValue(), change.getChangeType()));
            }
        }
    });


    ----------------------------------------
    SpringBoot 下预先加载配置项
    ----------------------------------------
    SpringBoot 大量采用了自动装配机制, 比如 DataSource 实例初始化. 当引入 Apollo 配置中心后, 是否也支持这个特性呢? 答案是肯定的, apollo.bootstrap.namespaces 属性指定的 namespace 将在 SpringContext 容器初始化时候就加载完毕, 这样在实例化 bean 时就可能使用 Apollo 配置项了. 需要在 application.properties 中设置下面两个属性:
    apollo.bootstrap.enabled = true
    apollo.bootstrap.namespaces = application,other_namespace

    ----------------------------------------
    方式 2: Spring 的 @Value 方式关联 appollo 配置项
    ----------------------------------------
    在代码层面该方式仅需要两个步骤:
    步骤 1: 在一个被@Configuration 注解的类上加 @EnableApolloConfig,  比如在 Application 入口类上加 @EnableApolloConfig. @EnableApolloConfig 负责将 apollo 的 namespace 注册到 Configuration 类中.
    步骤 2: 在程序中使用 @Value 引入这个配置项

        @Value("${timeout:1000}")
        private String timeout;


    需要说明的是:
    1. @EnableApolloConfig 注解必须和@Configuration 搭配使用, 如果没有指定注解参数, 对应的namespace为 apollo 的 "application" namespace, .
    2. 默认情况下, @Value 的属性会自动更新的, 如果不希望自动更新, 可以在 application.properties 设置:
    apollo.autoUpdateInjectedSpringProperties=false # 关闭自动更新 @Value 注解的属性


    ----------------------------------------
    方式 3: 结合 SpringBoot 的 @ConfigurationProperties 注解.
    ----------------------------------------


    ----------------------------------------
    方式 4. 使用 Apollo 的 @ApolloConfig 和 @ApolloConfigChangeListener
    ----------------------------------------
    这个方法其实和通过 API 方法非常类似, 仅仅是简化了代码.
    使用 @ApolloConfig 用来注入一个 apollo config 对象, 使用 @ApolloConfigChangeListener 用来注册一个监听事件.
    @ApolloConfig(namespace) 可以匹配 apollo 的命名空间, 如不写, 则指 application 命名空间.
    @ApolloConfigChangeListener(namespace) 更新时调用的方法, 如不写, 则指 application 命名空间.

    在代码层面该方式仅需要两个步骤:
    1. 在一个被@Configuration 注解的类上加 @EnableApolloConfig, 比如在 Application 入口类上加 @EnableApolloConfig.
    2. 增加一个 bean 类,在其中使用 @ApolloConfig 和 @ApolloConfigChangeListener 注入 config 对象和监听事件, 同时加上一个 @PostConstruct 方法来初始化 apollo 配置项原始值.

    @EnableApolloConfig
    @Component
    class ApolloConfigBean {
    
        @ApolloConfig //注入一个 Apollo Config 对象
        private Config appConfig;
    
        @PostConstruct // 在 ApolloConfigBean 实例化后, 立即获取 apollo 配置项值
        public void init() {
            timeout = appConfig.getIntProperty("timeout", 100);
        }
    
        private int timeout = -1;
    
        public int getTimeout() {
            return timeout;
        }
    
        @ApolloConfigChangeListener //注册一个监听事件
        private void onChange(ConfigChangeEvent changeEvent) {
            if (changeEvent.isChanged("timeout")) {
                timeout = Integer.parseInt(changeEvent.getChange("timeout")
                        .getNewValue());
            }
            System.out.println("onchange ");
        }
    }



    ----------------------------------------
    方式 5. Spring 项目通过 Environment
    ----------------------------------------



    ================================================
    参考
    ================================================
    Apollo 的基本使用方法
    http://ghoulich.xninja.org/2018/04/28/basic-usage-method-of-apollo/
    Java 客户端使用指南
    https://github.com/ctripcorp/apollo/wiki/Java 客户端使用指南
    微服务之 SpringCloud 架构第六篇(下)——配置中心(Apollo)
    https://blog.csdn.net/pilihaotian/article/details/82958386
    Apollo 应用之动态调整线上数据源 (DataSource)
    http://www.kailing.pub/article/index/arcid/198.html
    SpringBoot 整合携程 Apollo 配置管理中心
    https://www.cnblogs.com/hongdada/p/9015748.html
    携程 Apollo(阿波罗)配置中心在 Spring Boot 项目快速集成
    https://www.cnblogs.com/EasonJim/p/7649047.html
    Apollo-4-客户端-SDK-设计
    http://thinkinjava.cn/2018/06/Apollo-4-%E5%AE%A2%E6%88%B7%E7%AB%AF-SDK-%E8%AE%BE%E8%AE%A1/

  • 相关阅读:
    对文件上传使用表单验证
    文件上传
    自定义验证器
    WTForms常用的验证器
    Eclipse自动补全+常用快捷键
    JNI笔记
    cocos2d 2.2.6 win7下的配置
    cocos2d 3.6 win7下的配置
    python--文件删除、判断目录存在、字符串替换
    只是一个文件节点类为了项目的数据处理
  • 原文地址:https://www.cnblogs.com/harrychinese/p/apollo_java.html
Copyright © 2011-2022 走看看