如果一个应用部署在多台服务器上,一旦需要更改配置,就不得不在所有服务器上进行同样的更改,显然效率很低。借助 ACM,您可以为应用创建一个配置,并在程序中使用 ACM 的原生 API 监听此配置的变更。当您在 ACM 控制台更改此配置后,所有部署了该应用的服务器都会收到变更的配置内容,应用状态也随之刷新。

前提条件

背景信息

业务应用 myapp.jar 部署在生产环境的两台服务器上。该应用包含一个配置文件 app.cfg,配置文件里包含线程池大小(threadPoolSize)和日志级别(logLevel)这两个配置项。现在需要同时调整该应用在两台机器上的配置,并动态刷新应用的状态。此业务场景如下图所示:

配置内容为:

## app.cfg ##
threadPoolSize=5
logLevel=WARN

在本示例任务中,我们首先在 ACM 上为应用 myapp 创建了一个配置,并在程序中使用 ACM 的原生 API 监听这个配置的变更。当我们在 ACM 控制台上更改配置后,所有部署了该应用的服务器都会收到变更的配置内容,应用状态也随之刷新。

第 1 步:在 ACM 中创建配置

  1. 登录 ACM 控制台
  2. 在左侧导航栏中选择配置列表,然后在页面右上角单击 + 图标。
  3. 新建配置页面上输入以下内容,并单击发布
    • DataID:com.acm.myapp.app.cfg
    • Group:myapp
    • 配置内容:
      threadPoolSize=5
      logLevel=WARN

    如图所示:

第 2 步:使用 API 监听配置变更

  1. 运行以下命令来创建 Maven 工程,或者下载样例工程 myapp.zip
    说明 关于如何安装和使用 Maven,请参考 Maven 官方文档
    mvn archetype:generate -DgroupId=com.acm.sample -DartifactId=myapp -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

    创建的工程结构如下:

    myapp
    |-- pom.xml
    `-- src
        |-- main
        |   `-- java
        |       `-- com
        |           `-- acm
        |               `-- sample
        |                   `-- App.java
        `-- test
            `-- java
                `-- com
                    `-- mycompany
                        `-- app
                            `-- AppTest.java
  2. 在 pom.xml 中添加 ACM Client 原生 API 依赖。
    <dependencies>
         <dependency>
             <groupId>com.alibaba.edas.acm</groupId>
             <artifactId>acm-sdk</artifactId>
             <version>1.0.8</version>
         </dependency>
         <!--  有日志实现,下面可去掉  -->
         <dependency>
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-classic</artifactId>
             <version>1.1.7</version>
         </dependency>
     </dependencies>
  3. 在 pom.xml 中添加 maven-assembly-plugin 打包插件
    <plugin>
       <artifactId>maven-assembly-plugin</artifactId>
       <version>2.4</version>
       <configuration>
          <finalName>myapp</finalName>
          <descriptorRefs>
             <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <appendAssemblyId>false</appendAssemblyId>
          <archive>
             <manifest>
                <mainClass>com.acm.sample.App</mainClass>
             </manifest>
          </archive>
       </configuration>
       <executions>
          <execution>
             <id>make-assembly</id>
             <phase>package</phase>
             <goals>
                <goal>single</goal>
             </goals>
          </execution>
       </executions>
    </plugin>
  4. 使用 API 监听配置变更。

    说明 以下代码中的用户变量,例如 $endpoint$namespace$accesskey 等,可在 ACM 控制台的 命名空间页面查看,如下图所示。


    //-- App.java
    package com.acm.sample;
    
    import java.io.IOException;
    import java.io.StringReader;
    import java.util.Properties;
    import com.alibaba.edas.acm.listener.ConfigChangeListener;
    import com.alibaba.edas.acm.ConfigService;
    import com.alibaba.edas.acm.exception.ConfigException;
    
    public class App {
    
         private static Properties appCfg = new Properties();
    
         public static void initAndWatchConfig() {
             final String dataId = "com.acm.myapp.app.cfg";
             final String group = "myapp";
             final long timeoutInMills = 3000;
    
             // 从控制台命名空间管理中拷贝对应值
             Properties properties = new Properties();
             properties.put("endpoint", "$endpoint");
             properties.put("namespace", "$namespace");
             properties.put("accessKey", "$accessKey");
             properties.put("secretKey", "$secretKey");
    
             // 如果是加密配置,则添加下面两行进行自动解密
             // properties.put("openKMSFilter", true);
             // properties.put("regionId", "$regionId");
    
             ConfigService.init(properties);
    
             // 直接获取配置内容
             try {
                 String configInfo = ConfigService.getConfig(dataId, group, timeoutInMills);
                 appCfg.load(new StringReader(configInfo));
             } catch (ConfigException e1) {
                 e1.printStackTrace();
             } catch (IOException e) {
                 e.printStackTrace();
             }
    
             // 监听配置变化,获取最新推送值
             ConfigService.addListener(dataId, group, new ConfigChangeListener() {
                 public void receiveConfigInfo(String configInfo) {
                     try {
                         appCfg.load(new StringReader(configInfo));
                     } catch (Exception e) {
                         // process exception
                     }
                     refreshApp();
                 }
             });
         }
    
         public static void refreshApp() {
             System.out.println("current thread pool size: " + appCfg.getProperty("threadPoolSize"));
             System.out.println("current log level: " + appCfg.getProperty("logLevel"));
             System.out.println("");
         }
    
         public static void main(String[] args) {
             initAndWatchConfig();
    
             // 让主线程不退出
             while (true) {
                 try {
                     Thread.sleep(1000);
                 } catch (InterruptedException e) {
                 }
             }
         }
     }

第 3 步:部署并启动应用

  1. 将应用打成 Jar 包,并拷贝到两台服务器上。在项目根目录下执行以下打包命令
    mvn clean package
  2. 在 Shell 中部署并启动应用。

    ${JAVA_HOME}/java -cp myapp.jar com.acm.sample.App
说明 为了运行 Java 程序,服务器上必须安装 JDK 并设置环境变量 JAVA_HOME

第 4 步:在 ACM 控制台查询并更改配置

  1. 在 ACM 控制台的配置列表页面上,搜索第 1 步:在 ACM 中创建配置中创建的配置。
  2. 单击操作栏中的编辑
  3. 编辑配置页面上将配置内容更改为以下内容,并单击发布
    threadPoolSize=15
    logLevel=DEBUG
  4. 内容比较对话框中,确认配置更改无误,并单击确认发布



验证结果

发布配置之后,可以看到在两台部署的机器上,应用同时收到配置变更信息,并打印了以下信息。

current thread pool size: 15
current log level: DEBUG