Spring Cloud 配置中心 Apollo 入門

摘要: 原創出處 http://www.iocoder.cn/Spring-Cloud/Apollo/ 「芋道源碼」歡迎轉載,保留摘要,謝謝!



1. 概述

本文我們來學習如何在 Spring Cloud 中使用 Apollo 作爲配置中心,實現服務的統一配置管理。

FROM 《Apollo 設計文檔 —— Home》

Apollo(阿波羅)是攜程框架部門研發的分佈式配置中心,能夠集中化管理應用不同環境、不同集羣的配置,配置修改後能夠實時推送到應用端,並且具備規範的權限、流程治理等特性,適用於微服務配置管理場景。

在開始本文之前,胖友需要對 Apollo 進行簡單的學習。可以閱讀《Apollo 安裝部署》文章,將第一二小節看完,在本機搭建一個 Apollo 服務。

友情提示:因爲 Apollo 沒有對 Spring Cloud 進行集成,所以在使用上和在 Spring Boot 中差異性不大,因此本文內容上和《芋道 Spring Boot 配置中心 Apollo 入門》大致相同,嘿嘿~

2. 快速入門

示例代碼對應倉庫:labx-09-sc-apollo-demo

本小節,我們會在 Apollo 服務中定義配置,並使用 @ConfigurationProperties 和 @Value 註解,讀取該配置。

友情提示:如果胖友看過《芋道 Spring Boot 配置文件入門》「2. 自定義配置」小節,就會發現本小節是對標這塊的內容。

如果沒看過,也沒關係,艿艿只是提一下而已,嘿嘿。繼續往下看即可。

下面,我們來創建一個 labx-09-sc-apollo-demo 示例項目,進行快速入門。最終項目代碼如下圖所示:`labx-09-sc-apollo-demo` 項目

2.1 引入依賴

在 pom.xml 文件中,主要引入 Apollo 相關依賴。代碼如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>labx-09</artifactId>
        <groupId>cn.iocoder.springboot.labs</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>labx-09-sc-apollo-demo</artifactId>

    <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <spring.boot.version>2.2.4.RELEASE</spring.boot.version>
        <spring.cloud.version>Hoxton.SR1</spring.cloud.version>
    </properties>

    <!--
        引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,進行依賴版本的管理,防止不兼容。
        在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 開發團隊推薦了三者的依賴關係
     -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- 引入 Spring Cloud 基礎依賴 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-commons</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-context</artifactId>
        </dependency>

        <!-- 引入 SpringMVC 相關依賴,並實現對其的自動配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--  引入 Apollo 客戶端,內置對 Apollo 的自動化配置 -->
        <dependency>
            <groupId>com.ctrip.framework.apollo</groupId>
            <artifactId>apollo-client</artifactId>
            <version>1.5.1</version>
        </dependency>
    </dependencies>

</project>

通過引入 apollo-client 依賴,引入 Apollo 客戶端,並實現對 Apollo 的自動化配置。

友情提示:Apollo 並未提供單獨的 Spring Boot 項目,而是在 apollo-client 中直接提供對 Apollo 在 Spring Boot 自動配置的實現。

2.2 配置文件

在 application.yml 中,添加 Apollo 配置,如下:

server:
  port: 7070 # 避免和本地的 Apollo Portal 端口衝突

app:
  id: demo-application # 使用的 Apollo 的項目(應用)編號
apollo:
  meta: http://127.0.0.1:8080 # Apollo Meta Server 地址
  bootstrap:
    enabled: true # 是否開啓 Apollo 配置預加載功能。默認爲 false。
    eagerLoad:
      enable: true # 是否開啓 Apollo 支持日誌級別的加載時機。默認爲 false。
    namespaces: application # 使用的 Apollo 的命名空間,默認爲 application。
  • app.id 配置項,使用的 Apollo 的項目(應用)編號。稍後,我們在「2.3 創建 Apollo 配置」小節中進行創建。
  • apollo.meta 配置項,使用的 Apollo Meta Server 地址。
  • apollo.bootstrap.enabled 配置項,是否開啓 Apollo 配置預加載功能。默認爲 false。😈 這裏,我們設置爲 true,保證使用 @Value 和 @ConfigurationProperties 註解,可以讀取到來自 Apollo 的配置項。
  • apollo.bootstrap.eagerLoad.enable 配置項,是否開啓 Apollo 支持日誌級別的加載時機。默認爲 false。😈 這裏,我們設置爲 true,保證 Spring Boot 應用的 Logger 能夠使用來自 Apollo 的配置項。
  • apollo.bootstrap.namespaces 配置項,使用的 Apollo 的命名空間,默認爲 application。關於 Apollo 的概念,可見《Apollo 核心概念之“Namespace”》文章。

2.3 創建 Apollo 配置

在 Apollo 中創建 Apollo 配置,內容如下圖所示:創建 Apollo 配置

2.4 OrderProperties

創建 OrderProperties 配置類,讀取 order 配置項。代碼如下:

@Component
@ConfigurationProperties(prefix = "order")
public class OrderProperties {

    /**
     * 訂單支付超時時長,單位:秒。
     */
    private Integer payTimeoutSeconds;

    /**
     * 訂單創建頻率,單位:秒
     */
    private Integer createFrequencySeconds;

    // ... 省略 set/get 方法

}
  • 在類上,添加 @Component 註解,保證該配置類可以作爲一個 Bean 被掃描到。
  • 在類上,添加 @ConfigurationProperties 註解,並設置 prefix = "order" 屬性,這樣它就可以讀取前綴爲 order 配置項,設置到配置類對應的屬性上。

2.5 DemoController

創建 DemoController 類,提供測試 @ConfigurationProperties 和 @Value 注入配置的兩個 HTTP 接口。代碼如下:

@RestController
@RequestMapping("/demo")
public class DemoController {

    @Autowired
    private OrderProperties orderProperties;

    /**
     * 測試 @ConfigurationProperties 註解的配置屬性類
     */
    @GetMapping("/test01")
    public OrderProperties test01() {
        return orderProperties;
    }

    @Value(value = "${order.pay-timeout-seconds}")
    private Integer payTimeoutSeconds;
    @Value(value = "${order.create-frequency-seconds}")
    private Integer createFrequencySeconds;

    /**
     * 測試 @Value 註解的屬性
     */
    @GetMapping("/test02")
    public Map<String, Object> test02() {
        return new JSONObject().fluentPut("payTimeoutSeconds", payTimeoutSeconds)
                .fluentPut("createFrequencySeconds", createFrequencySeconds);
    }

}

2.6 DemoApplication

創建 DemoApplication 類,作爲應用啓動類。代碼如下:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class);
    }

}

2.7 簡單測試

① 使用 DemoApplication 啓動示例應用。在 IDEA 控制檯中,可以看到 Apollo 相關的日誌如下:

2020-03-01 14:42:54.155  INFO 74637 --- [           main] c.c.f.f.i.p.DefaultApplicationProvider   : App ID is set to demo-application by app.id property from System Property
2020-03-01 14:42:54.159  INFO 74637 --- [           main] c.c.f.f.i.p.DefaultServerProvider        : Loading /opt/settings/server.properties
2020-03-01 14:42:54.161  INFO 74637 --- [           main] c.c.f.f.i.p.DefaultServerProvider        : Environment is set to null. Because it is not available in either (1) JVM system property 'env', (2) OS env variable 'ENV' nor (3) property 'env' from the properties InputStream.
2020-03-01 14:42:54.161  INFO 74637 --- [           main] c.c.f.f.i.p.DefaultServerProvider        : Data Center is set to [yunai] by property 'idc' in server.properties.
2020-03-01 14:42:54.194  INFO 74637 --- [           main] c.c.f.a.i.DefaultMetaServerProvider      : Located meta services from apollo.meta configuration: http://127.0.0.1:8080!
2020-03-01 14:42:54.201  INFO 74637 --- [           main] c.c.f.apollo.core.MetaDomainConsts       : Located meta server address http://127.0.0.1:8080 for env UNKNOWN from com.ctrip.framework.apollo.internals.DefaultMetaServerProvider

② 使用瀏覽器,訪問 http://127.0.0.1:7070/demo/test01 接口,測試 @ConfigurationProperties 註解的配置屬性類,返回結果如下,符合預期:

{
    "payTimeoutSeconds": 120,
    "createFrequencySeconds": 120
}

② 使用瀏覽器,訪問 http://127.0.0.1:7070/demo/test02 接口,測試 @Value 註解的屬性,返回結果如下,符合預期:

{
    "payTimeoutSeconds": 120,
    "createFrequencySeconds": 120
}

3. 多環境配置

示例代碼對應倉庫:labx-09-sc-apollo-demo-profiles

《芋道 Spring Boot 配置文件入門》「6. 多環境配置」中,我們介紹如何基於 spring.profiles.active 配置項,在 Spring Boot 實現多環境的配置功能。在本小節中,我們會在該基礎之上,實現結合 Apollo 的多環境配置。

在 Apollo 中,我們可以通過搭建不同環境的 Config Service + Admin Service 服務。然後,在每個 application-${profile}.yaml 配置文件中,配置對應的 Config Service + Admin Service 服務即可。

下面,我們來創建一個 labx-09-sc-apollo-demo-profiles 示例項目,搭建一個結合 Apollo 的多環境的示例。最終項目代碼如下圖所示:`labx-09-sc-apollo-demo-profiles` 項目

3.1 創建 Apollo 配置

在 Apollo 中創建 Apollo 配置,創建一個 AppId 爲 demo-application-profiles 的項目,並配置 DEV(開發環境)和 PRO(生產環境)兩套配置。如下圖所示:

  • 創建 Apollo 配置(開發)
  • 創建 Apollo 配置(生產)

這裏,我們通過不同環境,使用不同 server.port 配置項。這樣, Spring Cloud 項目啓動後,從日誌中就可以看到生效的服務器端口,嘿嘿~從而模擬不同環境,不同配置。

3.2 引入依賴

「2.1 引入依賴」一致,可以點擊 pom.xml 文件查看。

3.3 配置文件

在 resources 目錄下,創建 2 個配置文件,對應不同的環境。如下:

  • application-dev.yaml,開發環境。

    app:
      id: demo-application-profiles # 使用的 Apollo 的項目(應用)編號
    apollo:
      meta: http://127.0.0.1:8080 # Apollo Meta Server 地址
      bootstrap:
        enabled: true # 是否開啓 Apollo 配置預加載功能。默認爲 false。
        eagerLoad:
          enable: true # 是否開啓 Apollo 支持日誌級別的加載時機。默認爲 false。
        namespaces: application # 使用的 Apollo 的命名空間,默認爲 application。
    
    • 「2.2 配置文件」不同的點,重點是 apollo.meta 配置項,設置爲 DEV 環境的 Apollo Meta Server 地址。
  • application-prod.yaml,生產環境。

    app:
      id: demo-application-profiles # 使用的 Apollo 的項目(應用)編號
    apollo:
      meta: http://127.0.0.1:18080 # Apollo Meta Server 地址
      bootstrap:
        enabled: true # 是否開啓 Apollo 配置預加載功能。默認爲 false。
        eagerLoad:
          enable: true # 是否開啓 Apollo 支持日誌級別的加載時機。默認爲 false。
        namespaces: application # 使用的 Apollo 的命名空間,默認爲 application。
    
    • 「2.2 配置文件」不同的點,重點是 apollo.meta 配置項,設置爲 PROD 環境的 Apollo Meta Server 地址。

另外,我們會創建 application.yaml 配置文件,放不同環境的相同配置。例如說,spring.application.name 配置項,肯定是相同的啦。配置如下:

#server:
spring:
  application:
    name: demo-application

3.4 DemoApplication

創建 DemoApplication 類,配置 @SpringBootApplication 註解即可。代碼如下:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class);
    }

}

3.5 簡單測試

下面,我們使用命令行參數進行 --spring.profiles.active 配置項,實現不同環境,讀取不同配置文件。

經過測試:

  • 使用命令行參數進行 --spring.profiles.active 配置,對 application.yaml 配置文件無效
  • 使用 VM 參數進行 -Dspring.profiles.active 配置愛,對 application.yaml 配置文件有效

具體的原因還不知道,先暫時這麼解決哈~

① 開發環境示例:直接在 IDEA 中,增加 -Dspring.profiles.active=dev 到 VM options 中。如下圖所示:IDEA 配置 - dev

啓動 Spring Boot 應用,輸出日誌如下:

# 省略其它日誌...
2020-01-27 12:08:57.051  INFO 27951 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8081 (http)
  • Tomcat 啓動在 8081 端口,符合讀取 DEV 環境的配置。

② 生產環境示例:直接在 IDEA 中,增加 -Dspring.profiles.active=dev 到 VM options 中。如下圖所示:IDEA 配置 - prod

啓動 Spring Boot 應用,輸出日誌如下:

# 省略其它日誌...
2020-01-27 12:11:31.159  INFO 28150 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8084 (http)
  • Tomcat 啓動在 8084 端口,符合讀取 PROD 環境的配置。

另外,關於 Spring Boot 應用的多環境部署,胖友也可以看看《芋道 Spring Boot 持續交付 Jenkins 入門》文章。

4. 自動刷新配置

示例代碼對應倉庫:labx-09-sc-apollo-demo-auto-refresh

在上面的示例中,我們已經實現從 Apollo 讀取配置。那麼,在應用已經啓動的情況下,如果我們將讀取的 Apollo 的配置進行修改時,應用是否會自動刷新本地的配置呢?

在上面的示例中,我們已經實現從 Apollo 讀取配置。那麼,在應用已經啓動的情況下,如果我們將讀取的 Apollo 的配置進行修改時,應用是否會自動刷新本地的配置呢?答案是,針對 @Value 註解的屬性是的,針對 @ConfigurationProperties 註解的配置類需要做特殊處理

下面,我們從「2. 快速入門」小節的 labx-09-sc-apollo-demo 項目,複製出 labx-09-sc-apollo-demo-auto-refresh 項目,用於演示 Apollo 的自動刷新配置的功能。最終項目代碼如下圖所示:`labx-09-sc-apollo-demo-auto-refresh` 項目

4.1 簡單測試

① 使用 DemoApplication 啓動示例應用。

② 獲得目前在 Apollo 的配置內容爲:

order.pay-timeout-seconds: 60 # 訂單支付超時時長,單位:秒。
order.create-frequency-seconds: 120 # 訂單創建頻率,單位:秒

使用 curl 命令,請求 DemoController 提供的兩個測試接口,過程如下:

# 測試 `@ConfigurationProperties` 註解的配置屬性類
$ curl http://127.0.0.1:8080/demo/test01
{"payTimeoutSeconds":60,"createFrequencySeconds":120}

# 測試 `@Value` 註解的屬性
$ curl http://127.0.0.1:8080/demo/test02
{"payTimeoutSeconds":60,"createFrequencySeconds":120}

③ 修改在 Apollo 的配置內容爲:

order.pay-timeout-seconds: 60 # 訂單支付超時時長,單位:秒。
order.create-frequency-seconds: 480 # 訂單創建頻率,單位:秒

此時,我們可以看到 IDEA 控制檯打印出了好多 Apollo 相關的日誌,如下:

2020-03-01 15:45:09.858  INFO 75990 --- [Apollo-Config-1] c.f.a.s.p.AutoUpdateConfigChangeListener : Auto update apollo changed value successfully, new value: 480, key: order.pay-timeout-seconds, beanName: demoController, field: cn.iocoder.springcloud.labx09.apollodemo.controller.DemoController.payTimeoutSecond
  • 可以看到 DemoController.payTimeoutSecond 被修改成了 480 的提示。

使用 curl 命令,請求 DemoController 提供的兩個測試接口,過程如下:

# 測試 `@ConfigurationProperties` 註解的配置屬性類
$ curl http://127.0.0.1:8080/demo/test01
{"payTimeoutSeconds":120,"createFrequencySeconds":60}

# 測試 `@Value` 註解的屬性
$ curl http://127.0.0.1:8080/demo/test02
{"payTimeoutSeconds":480,"createFrequencySeconds":60}
  • 使用 @ConfigurationProperties 註解的失敗刷新,使用 @Value 註解的成功刷新。

4.2 ApolloPropertiesRefresher

創建 ApolloPropertiesRefresher 類,監聽 Apollo 的配置變更,發佈 Spring Cloud EnvironmentChangeEvent 事件,從而解決 @ConfigurationProperties 註解的屬性的刷新的問題。代碼如下:

@Component
public class ApolloPropertiesRefresher implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @ApolloConfigChangeListener(value = ConfigConsts.NAMESPACE_APPLICATION)
    public void onChange(ConfigChangeEvent changeEvent) {
        this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
    }

}

在 #onChange(ConfigChangeEvent changeEvent) 方法上,我們添加了 Apollo 定義的 @ApolloConfigChangeListener 註解,這樣可以實現對 Apollo 配置的監聽,從而發佈 EnvironmentChangeEvent 事件。

友情提示:更多 @ApolloConfigChangeListener 註解的分享,胖友可以閱讀《芋道 Spring Boot 配置中心 Apollo 入門》文章的「4.8 Apollo 配置監聽器」小節

4.3 重新測試

① 使用 DemoApplication 啓動示例應用。

② 獲得目前在 Apollo 的配置內容爲:

order.pay-timeout-seconds: 60 # 訂單支付超時時長,單位:秒。
order.create-frequency-seconds: 120 # 訂單創建頻率,單位:秒

使用 curl 命令,請求 DemoController 提供的兩個測試接口,過程如下:

# 測試 `@ConfigurationProperties` 註解的配置屬性類
$ curl http://127.0.0.1:8080/demo/test01
{"payTimeoutSeconds":60,"createFrequencySeconds":120}

# 測試 `@Value` 註解的屬性
$ curl http://127.0.0.1:8080/demo/test02
{"payTimeoutSeconds":60,"createFrequencySeconds":120}

③ 修改在 Apollo 的配置內容爲:

order.pay-timeout-seconds: 60 # 訂單支付超時時長,單位:秒。
order.create-frequency-seconds: 480 # 訂單創建頻率,單位:秒

使用 curl 命令,請求 DemoController 提供的兩個測試接口,過程如下:

# 測試 `@ConfigurationProperties` 註解的配置屬性類
$ curl http://127.0.0.1:8080/demo/test01
{"payTimeoutSeconds":480,"createFrequencySeconds":60}

# 測試 `@Value` 註解的屬性
$ curl http://127.0.0.1:8080/demo/test02
{"payTimeoutSeconds":480,"createFrequencySeconds":60}
  • 使用 @ConfigurationProperties 註解的成功刷新,使用 @Value 註解的成功刷新。完美~

ps:還有一種解決方案,基於 Spring Cloud RefreshScope 來解決,可以參考 SpringBootApolloRefreshConfig 的代碼,如下圖所示:SpringBootApolloRefreshConfig 解析圖

友情提示:具體的實現原理,可以閱讀《@RefreshScope 那些事》文章,艿艿暫時還沒去深入,嘿嘿~

4.4 日誌級別刷新

「4.2 ApolloPropertiesRefresher」小節中,我們實現了監聽 Apollo 配置的變更,發佈 Spring Cloud EnvironmentChangeEvent 事件,而 Spring Cloud LoggingRebinder 會監聽該事件,重新設置日誌級別。整體流程如下圖所示:日誌級別刷新

4.5 再次測試

① 在 DemoController 類中,增加如下 API 接口。代碼如下:

private Logger logger = LoggerFactory.getLogger(getClass());

@GetMapping("/logger")
public void logger() {
    logger.debug("[logger][測試一下]");
}
  • 如果 DemoController 對應的 Logger 日誌級別是 DEBUG 以上,則無法打印出日誌。

② 在 Apollo 中,增加 logging.level.cn.iocoder.springcloud.labx09.apollodemo.controller.DemoController 配置項爲 INFO

③ 使用 DemoApplication 啓動示例應用。

請求 http://127.0.0.1:8080/demo/logger 接口,控制檯並未打印日誌,因爲當前日誌級別是 INFO。

④ 在 Apollo 中,修改 logging.level.cn.iocoder.springcloud.labx09.apollodemo.controller.DemoController 配置項爲 INFO,無需重啓應用。

請求 http://127.0.0.1:8080/demo/logger 接口,控制檯打印日誌,因爲當前日誌級別是 DEBUG。日誌內容如下:

2020-03-01 16:44:13.073 DEBUG 77189 --- [nio-7070-exec-2] c.i.s.l.a.controller.DemoController      : [logger][測試一下]
  • 符合預期。

5. 配置加密

示例代碼對應倉庫:labx-09-sc-apollo-demo-jasypt

考慮到安全性,我們可能最好將配置文件中的敏感信息進行加密。例如說,MySQL 的用戶名密碼、第三方平臺的 Token 令牌等等。不過,Apollo 暫時未內置配置加密的功能。官方文檔說明如下:

FROM https://github.com/ctripcorp/apollo/wiki/FAQ

7. Apollo 是否支持查看權限控制或者配置加密?

從 1.1.0 版本開始,apollo-portal 增加了查看權限的支持,可以支持配置某個環境只允許項目成員查看私有 Namespace 的配置。

這裏的項目成員是指:

  1. 項目的管理員
  2. 具備該私有Namespace在該環境下的修改或發佈權限

配置方式很簡單,用超級管理員賬號登錄後,進入 管理員工具 - 系統參數 頁面新增或修改 configView.memberOnly.envs配置項即可。

configView.memberOnly.envs

配置加密可以參考 spring-boot-encrypt demo項目

因此,我們暫時只能在客戶端進行配置的加解密。這裏,我們繼續採用在《芋道 Spring Boot 配置文件入門》「8. 配置加密」小節中使用的 Jasypt

下面,我們來創建一個 labx-09-sc-apollo-demo-jasypt 示例項目,使用 Apollo + Jasypt 搭建一個配置加密的示例。最終項目代碼如下圖所示:`labx-09-sc-apollo-demo` 項目

5.1 引入依賴

「2.1 引入依賴」的基礎之上,額外引入 Jasypt 相關依賴如下:

<!-- 實現對 Jasypt 實現自動化配置 -->
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.2</version>
</dependency>

<!-- 方便等會寫單元測試 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

完整的,可以點擊 pom.xml 文件查看。

5.2 創建 Apollo 配置

在 Apollo 中創建 Apollo 配置,內容如下圖所示:創建 Apollo 配置

這裏爲了測試簡便,我們直接添加加密祕鑰 jasypt.encryptor.password 配置項在該 Apollo 配置中。如果爲了安全性更高,實際建議把加密祕鑰和配置隔離。不然,如果配置泄露,豈不是可以拿着加密祕鑰,直接進行解密。

5.3 配置文件

在 application.yml 中,添加 Apollo 配置,如下:

server:
  port: 7070 # 避免和本地的 Apollo Portal 端口衝突

app:
  id: demo-application-jasypt # 使用的 Apollo 的項目(應用)編號
apollo:
  meta: http://127.0.0.1:8080 # Apollo Meta Server 地址
  bootstrap:
    enabled: true # 是否開啓 Apollo 配置預加載功能。默認爲 false。
    eagerLoad:
      enable: true # 是否開啓 Apollo 支持日誌級別的加載時機。默認爲 false。
    namespaces: application # 使用的 Apollo 的命名空間,默認爲 application。

5.4 DemoApplication

創建 DemoApplication 類,作爲應用啓動類。代碼如下:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class);
    }

}

5.5 JasyptTest

創建 JasyptTest 測試類,使用 Jasypt 將配置項的值進行加密。代碼如下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class JasyptTest {

    @Autowired
    private StringEncryptor encryptor;

    @Test
    public void encode() {
        // 第一個加密
        String password = "woshimima";
        System.out.println(encryptor.encrypt(password));

        // 第二個加密
        password = "bushimima";
        System.out.println(encryptor.encrypt(password));
    }

    @Value("${xxx-password:}")
    private String xxxPassword;

    @Test
    public void print() {
        System.out.println(xxxPassword);
    }

}

下面,我們進行下簡單測試。

① 首先,執行 #encode() 方法,手動使用 Jasypt 將 "woshimima" 和 "bushimima" 進行加密,獲得加密結果。加密結果如下:

// "woshimima" 的加密結果
yCJ8JgVNG8Ns+vikAvZBKfJu/7LVejQWzwMxyoVFoR8=
// "bushimima" 的加密結果
NGgajNjjhKcgm7ncXvdVNsShSsueysdcCOTbOmtHXRc=

② 然後,將 "woshimima" 加密結果 "yCJ8JgVNG8Ns+vikAvZBKfJu/7LVejQWzwMxyoVFoR8=",賦值到 Apollo 的 xxx-password 配置項中。如下圖所示:修改 Apollo 配置項

之後,執行 #print() 方法,自動使用 Jasypt 將 xxx-password 配置項解密。解密結果如下:

woshimima
  • 成功正確解密,符合預期。

5.6 DemoController

創建 DemoController 類,提供查詢 xxx-password 配置項的 HTTP 接口。代碼如下:

@RestController
@RequestMapping("/demo")
@RefreshScope
public class DemoController {

    @Value("${xxx-password:}")
    private String xxxPassword;

    @GetMapping("/test")
    public String test() {
        return xxxPassword;
    }

}

下面,我們進行下簡單測試。

① 使用 DemoApplication 啓動示例應用。

② 訪問 http://127.0.0.1:7070/demo/test 地址,返回結果爲 bushimima,符合預期。

5.7 補充說明

目前測試下來,在將 Jasypt 集成進來時,Apollo 的「4. 自動配置刷新」功能,竟然失效了。

  • 具體的驗證,胖友可以將 jasypt-spring-boot-starter 依賴設置成 <scope>test</scope>,並是使用 DemoController 進行測試。
  • 具體的原因,艿艿暫時沒去調試與研究,有了解的胖友,麻煩告知下喲。在 issues#2162 中,也有其它胖友提到該問題。

如果說,胖友暫時不需要自動配置刷新功能的話,可以考慮選擇使用 Jasypt 集成。如果需要的話,那麼就等待官方支持吧,暫時不要考慮使用 Jasypt 咧。

示例代碼對應倉庫:lab-45-apollo-demo-multi

《芋道 Spring Boot 配置文件入門》「9. 配置加載順序」小節,我們瞭解了 Spring Boot 自帶的配置加載順序。本小節,我們來看看來自 Apollo 的配置,在其中的順序。同時,我們將配置多個 Apollo Namespace 命名空間,看看它們互相之間的加載順序。

下面,我們來搭建一個用於測試配置加載順序的示例。

6. 配置加載順序

示例代碼對應倉庫:labx-09-sc-apollo-demo-multi

《芋道 Spring Boot 配置文件入門》「9. 配置加載順序」小節,我們瞭解了 Spring Boot 自帶的配置加載順序。本小節,我們來看看來自 Apollo 的配置,在其中的順序。同時,我們將配置多個 Apollo Namespace 命名空間,看看它們互相之間的加載順序。

下面,我們來創建一個 labx-09-sc-apollo-demo-multi 示例項目,搭建一個用於測試配置加載順序的示例。最終項目代碼如下圖所示:labx-09-sc-apollo-demo-multi 項目

6.1 創建 Apollo 配置

在 Apollo 中創建 Apollo 配置,內容如下圖所示:創建 Apollo 配置

6.2 引入依賴

「2.1 引入依賴」一致,可以點擊 pom.xml 文件查看。

6.3 配置文件

在 application.yml 中,添加 Apollo 配置,如下:

server:
  port: 7070 # 避免和本地的 Apollo Portal 端口衝突

app:
  id: demo-application-multi # 使用的 Apollo 的項目(應用)編號
apollo:
  meta: http://127.0.0.1:8080 # Apollo Meta Server 地址
  bootstrap:
    enabled: true # 是否開啓 Apollo 配置預加載功能。默認爲 false。
    eagerLoad:
      enable: true # 是否開啓 Apollo 支持日誌級別的加載時機。默認爲 false。
    namespaces: application, db # 使用的 Apollo 的命名空間,默認爲 application。

6.4 DemoApplication

創建 DemoApplication 類,作爲應用啓動類。代碼如下:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        // 啓動 Spring Boot 應用
        ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class);

        // 查看 Environment
        Environment environment = context.getEnvironment();
        System.out.println(environment);
    }

}

在代碼中,我們去獲取了 Spring Environment 對象,因爲我們要從其中獲取到 PropertySource 配置來源。DEBUG 運行 Application,並記得在 System.out.println(environment); 代碼塊打一個斷點,可以看到如下圖的調試信息:調試信息

  • 對於 apollo.bootstrap 對應一個 CompositePropertySource 對象,即使有對應多個 Apollo Namespace。並且,多個 Namespace 是按照在 apollo.bootstrap.namespaces 配置順序。
  • 所有 Apollo 對應的 PropertySource 對象,優先級非常高,目前看下來僅僅低於 server.ports 對應的 MapPropertySource。基本上,我們可以認爲是最高優先級了。

6.5 補充說明

搞懂配置加載順序的作用,很多時候是解決多個配置來源,裏面配置了相同的配置項。艿艿建議的話,儘量避免出現相同配置項,排查起來還挺麻煩的。

不過所幸,在日常開發中,我們也很少會設置相同的配置項 😜。

6.6 彩蛋

至此,我們已經完成如何在 Spring Cloud 使用 Apollo 的學習。如下是 Apollo 相關的官方文檔:

如果,對源碼感興趣的胖友,可以看看《Apollo 源碼解析》噢。

如果,想要在 Spring Boot 項目中使用 Apollo 作爲配置中心的胖友,可以閱讀《芋道 Spring Boot 配置中心 Apollo 入門》文章。

 

7 驗證補充說明

參考「芋道源碼」技術博客,驗證完成了apollo示例代碼,並且實現了將ruoyi-cloud框架進行了apollo配置。以下是實現源碼地址:

1、文中基礎示例:https://github.com/muziye2013/SpringBoot-Labs/tree/master/labx-09

2、關於apollo多環境配置的其他參考:https://www.jianshu.com/p/94c1a5a72c5b

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章