= Spring Cloud AliCloud ACM

Spring Cloud AliCloud ACM 提供了和阿里云上的ACM的集成。使得在项目中如果需要上云的用户可以非常方便无缝的对接阿里云，来享受云端提供的稳定服务。

=== 快速开始

为了能够在本地开发时可以使用和云上具有相同功能的ACM服务，我们提供了用于本地开发测试的轻量版配置中心。轻量版配置中心你可以理解为用于方便的本地开发测试的Saas平台。

==== 基于properties文件扩展名的配置

===== 轻量版配置中心服务端初始化

1、轻量版配置中心的下载和启动方式可参考 https://help.aliyun.com/document_detail/44163.html?spm=a2c4g.11186623.6.677.5f206b82Z2mTCF[这里]

2、启动好轻量版配置中心之后，在控制台中添加如下的配置。注意data id是以 properties为扩展名(默认的文件扩展名方式)。

[source,subs="normal"]
----
Group:      DEFAULT_GROOUP

DataId:     acm-config.properties

Content:    user.name=alibaba
            user.age=56
----

===== 客户端使用方式

为了能够在应用程序中使用ACM作为Sping Cloud Config的后端存储服务，在您构建Spring Boot 应用的同时添加一个Spring Boot Starter org.springframework.cloud:spring-cloud-starter-alicloud-acm。以下是一个基础的maven 依赖配置:

[source,xml]
----
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.5.RELEASE</version>
    <relativePath/>
</parent>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>0.2.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-alicloud-acm</artifactId>
    </dependency>
     <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
</dependencies>
----

现在你就可以创建一个标准的Spring Boot的应用。

[source,java]
----
@SpringBootApplication
public class ProviderApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(ProviderApplication.class, args);
        String userName = applicationContext.getEnvironment().getProperty("user.name");
        String userAge = applicationContext.getEnvironment().getProperty("user.age");
        System.err.println("user name :"+userName+"; age: "+userAge);
    }
}
----

spring-cloud-starter-alicloud-acm 对于ACM服务端的基础配置有默认值(默认配置绑定到的ip和端口为127.0.0.1和8080)，因此在运行此Example 之前， 你只需在 bootstrap.properties 配置文件配置spring.application.name即可，例如：

[source,properties]
----
spring.application.name=acm-config #注意，spring.application.name 必须要放在bootstrap.properties中
----

启动这个Example，可以在控制台看到打印出的值正是我们在轻量版配置中心上预先配置的值。

[source,subs="normal"]
----
2018-11-05 11:41:50.661  INFO 1541 --- [main] com.alibaba.demo.normal.ProviderApp      : Started ProviderApp in 15.809 seconds (JVM running for 16.513)
user name :alibaba; age: 56
2018-11-05 11:41:50.710  INFO 1541 --- [gPullingdefault] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@1f854e9e: startup date [Mon Nov 05 11:41:50 CST 2018]; root of context hierarchy
----

==== 基于yaml文件扩展名的配置

spring-cloud-starter-alicloud-acm 默认对文件扩展名为properties的支持，如果你习惯使用yaml格式来作为您的基础配置，也是可以支持的。这个时候你只需要在bootstrap.properties配置文件中显示的来声明使用的文件扩展名，如下所示

[source,properties]
----
spring.application.name=acm-config
spring.cloud.nacos.config.file-extension=yaml #显示的声明使用的文件扩展名
----

同时还需在轻量版配置中心的控制台新增一个dataid为yaml为扩展名的配置，如下所示：

[source,subs="normal"]
----
Group:      DEFAULT_GROUP

DataId:     acm-config.yaml

Content:    user.name: yaml-alibaba
            user.age:  102
----

完成之后，重启测试程序，可以在控制台看到输出的结果的值。

[source,subs="normal"]
----
2018-11-05 11:50:13.829  INFO 1674 --- [main] com.alibaba.demo.normal.ProviderApp      : Started ProviderApp in 15.091 seconds (JVM running for 15.626)
user name :yaml-alibaba; age: 102
2018-11-05 11:50:13.868  INFO 1674 --- [gPullingdefault] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@7f64acf5: startup date [Mon Nov 05 11:50:13 CST 2018]; root of context hierarchy
----

==== 支持配置的动态更新

spring-cloud-starter-alicloud-acm 也支持配置的动态更新，如下所示，当变更user.name时，应用程序中能够获取到最新的值：

[source,subs="normal"]
----
user name :yaml-alibaba; age: 102
user name :yaml-alibaba; age: 102
2018-11-05 11:52:15.192  INFO 1707 --- [gPullingdefault] o.s.boot.SpringApplication               : Started application in 0.162 seconds (JVM running for 26.869)
2018-11-05 11:52:15.193  INFO 1707 --- [gPullingdefault] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@36b222ff: startup date [Mon Nov 05 11:52:15 CST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@5cfd2308
2018-11-05 11:52:15.193  INFO 1707 --- [gPullingdefault] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@5cfd2308: startup date [Mon Nov 05 11:52:15 CST 2018]; root of context hierarchy
//感知到配置发生变更
user name :yaml-alibaba-update; age: 1020
----

==== 可支持profile粒度的配置

spring-cloud-starter-alicloud 在加载配置的时候，不仅仅加载了以dataid为${spring.application.name}.${file-extension:properties}为前缀的基础配置，还加载了dataid为${spring.application.name}-${profile}.${file-extension:properties}的基础配置。在我们日常开发中如果遇到多套环境下的不同配置，我们可以打开Spring自带的配置功能，放置在application.properties 配置文件中。如下所示：

[sources,properties]
----
spring.profiles.active=${deploy.env}
----

其中 ${deploy.env}变量的值可以在启动应用时通过-Ddeploy.env=*****来动态指定。比如现在在轻量版配置中心上新增了一个dataid为：acm-config-develop.yaml的基础配置，如下所示：

[source,subs="normal"]
----
Group:      DEFAULT_GROUP

DataId:     acm-config-develop.yaml

Content:    deploy.env: develop
----

同时启动应用的时候通过-Ddeploy.env=develop 来指定当前spring.profiles.active的值。

启动 Spring Boot 应用测试的代码如下：

[source,java]
----
@SpringBootApplication
public class ProviderApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(ProviderApp.class, args);

        while (true) {
            String userName = applicationContext.getEnvironment().getProperty("user.name");
            String userAge = applicationContext.getEnvironment().getProperty("user.age");
            //获取当前的部署环境
            String deployEnv = applicationContext.getEnvironment().getProperty("deploy.env");
            System.err.println("Deploy Env:"+deployEnv+"\n \t user name :" + userName + "; age: " + userAge);
            TimeUnit.SECONDS.sleep(1);
        }
    }
}
----

启动后，可见控制台的输出结果：

[source,subs="normal"]
----
2018-11-05 14:06:25.898  INFO 1852 --- [main] com.alibaba.demo.normal.ProviderApp      : Started ProviderApp in 14.947 seconds (JVM running for 15.471)
Deploy Env:develop
 	user name :yaml-alibaba-update; age: 1020
2018-11-05 14:06:25.939  INFO 1852 --- [gPullingdefault] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@75d62d18: startup date [Mon Nov 05 14:06:25 CST 2018]; root of context hierarchy
2018-11-05 14:06:25.967  INFO 1852 --- [gPullingdefault] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
----

如果我们要切换到生产环境，那么只需要更改启动的-Ddeploy.env=product 参数即可。前提是生产环境 模式下轻量版配置中心已经添加了该环境的基础配置。例如dataid为：acm-config-product.yaml的配置：

[source,subs="normal"]
----
Group:      DEFAULT_GROUP

DataId:     acm-config-product.yaml

Content:    deploy.env: Product
----

以-Ddeploy.env=product 启动测试程序，输出结果如下：

[source,subs="normal"]
----
2018-11-05 14:10:05.481  INFO 1857 --- [gPullingdefault] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@455d34c2: startup date [Mon Nov 05 14:10:05 CST 2018]; root of context hierarchy
Deploy Env:Product
 	user name :yaml-alibaba-update; age: 1020
2018-11-05 14:10:06.798  INFO 1857 --- [      Thread-20] ConfigServletWebServerApplicationContext : Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@3899782c: startup date [Mon Nov 05 14:10:01 CST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@245b4bdc
----

==== 基于组级别配置的高级功能

当你习惯使用application.properties 或者 application.yaml 来作为你的配置时，为了能够区分其他应用的配置，这个时候可以开启 spring-cloud-starter-alicloud-acm 提供的基于组级别的配置。即只需在bootstrap.properties配置文件中添加spring.application.group配置来标识应用所属的分组即可。如下所示：

[source,properties]
----
spring.application.group=com.infrastructure.alibaba
----

这个时候注意在轻量版配置中心填写的dataid的格式为：

 ${spring.application.group}:application.${file-extension}

如下所示:

[source,subs="normal"]
----
Group:      DEFAULT_GROUP

DataId:     com.infrastructure.alibaba:application.yaml

Content:    owner.group: infrastructure
----

启动 Spring Boot 应用测试的代码如下：

[source,java]
----
@SpringBootApplication
public class ProviderApp {

    public static void main(String[] args) throws Exception{
        ConfigurableApplicationContext applicationContext = SpringApplication.run(ProviderApp.class, args);

        while (true) {
            String userName = applicationContext.getEnvironment().getProperty("user.name");
            String userAge = applicationContext.getEnvironment().getProperty("user.age");
            String deployEnv = applicationContext.getEnvironment().getProperty("deploy.env");
            //获取当前应用所属的组
            String ownerGroup = applicationContext.getEnvironment().getProperty("owner.group");
            System.err.println("Deploy Env:"+deployEnv+"; in group :"+ownerGroup+"\n \tuser name :" + userName + "; age: " + userAge);
            TimeUnit.SECONDS.sleep(1);
        }

    }
}
----

测试输出的结果如下：

[source,subs="normal"]
----
2018-11-05 14:34:28.059  INFO 1902 --- [main] com.alibaba.demo.normal.ProviderApp      : Started ProviderApp in 15.431 seconds (JVM running for 16.008)
Deploy Env:product; in group :Infrastructure
 	user name :yaml-alibaba-update; age: 1020
2018-11-05 14:34:28.109  INFO 1902 --- [gPullingdefault] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@4846b0aa: startup date [Mon Nov 05 14:34:28 CST 2018]; root of context hierarchy
----
