IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 深入淺出 Spring Boot 多重設定檔管裡 (Spring Profiles) -> 正文阅读

[Java知识库]深入淺出 Spring Boot 多重設定檔管裡 (Spring Profiles)

在任何一套開發框架中,?多環境管裡?通常是重要的核心功能之一,當然在 Spring 框架中也不例外,這裡我們稱為?Spring Profiles?設定檔。這個功能說起來簡單,但實作起來卻很容易會不小心亂掉,這篇文章我打算來好好的梳理一番,把觀念搞懂,管裡才不會亂掉。

建立範例應用程式

  1. 使用 Spring Boot CLI 快速建立專案 (也可以用?Spring Initializr?建立)

    spring init --dependencies=web --groupId=com.duotify sbprofile1

    使用 Visual Studio Code 開啟該專案

    code sbprofile1
  2. 加入一個?HomeController?控制器

    檔名路徑:?src/main/java/com/duotify/sbprofile1/controllers/HomeController.java

    package com.duotify.sbprofile1.controllers;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HomeController {
        @GetMapping("/")
        public String home() {
            return "Hello World";
        }
    }
  3. 測試執行

    mvn clean spring-boot:run

    補充說明: 你可以在?pom.xml?的?<build>?底下新增一個?<defaultGoal>spring-boot:run</defaultGoal>?設定,未來就只要打?mvn?就會自動啟動 Spring Boot 執行喔! :+1:

    使用 cURL 測試

    $ curl localhost:8080
    Hello World

理解設定檔(Profiles)的真正含意

由於 Spring 框架有一大堆抽象概念,不好好花點時間研究,就會有很多魔鬼般的細節無法理解。本文所提到的 Spring Profiles 原本是一個很簡單的概念,但是在寫 Spring Boot 的時候卻有非常多種變化,多到可以讓你腦袋打結那種。

我們先從最簡單、最抽象的概念開始講起。

所謂?Profile?(設定檔) 通常有個?名字?(Profile Name),這個?名字?代表一組?應用程式配置?。你可以透過一個簡單的?設定名稱?(Profile Name),快速的切換?應用程式配置?,就這麼簡單!

其中?應用程式配置?包含了兩層含意:

  1. 組態配置(Configuration)

    所謂?組態配置?其實就是像?src/main/resources/application.properties?這種屬性定義檔。

  2. 應用程式元件組合(Components combination)

    所謂?應用程式元件組合?就是指應用程式中有哪些「元件」要啟用,你可以在?執行時期?透過簡單的參數,決定本次執行要用什麼?Profile?來啟動應用程式。

使用?Profile?來管裡?應用程式配置?,最常見的例子,就是用在「多環境」部署上,例如你有公司內部的「測試環境」與客戶提供的「正式環境」,兩者的組態設定通常都不太一樣,但也有些一樣的地方。此時,我們就可以透過多個?Profile?來管裡這些差異,抽象化之後,我們只要知道?設定名稱?(Profile Name)就可以切換不同環境。

如何使用應用程式屬性(Application Properties)

在理解如何?管裡多個設定檔?之前,應該要先瞭解?應用程式屬性?(Application Properties)應該怎麼用。

體驗的步驟如下:

  1. 編輯?src/main/resources/application.properties?屬性檔

    加入一個?my.profile?屬性值

    my.profile=dev
  2. 調整?HomeController?控制器,加入一個私有欄位(Private Field),並透過?@Value?標注來注入一個?my.profile?屬性值

    檔名路徑:?src/main/java/com/duotify/sbprofile1/controllers/HomeController.java

    package com.duotify.sbprofile1.controllers;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HomeController {
    
        @Value("${my.profile}")
        private String myProfile;
    
        @GetMapping("/")
        public String home() {
            return "Hello World: " + this.myProfile;
        }
    }
  3. 測試執行

    mvn clean spring-boot:run

    使用 cURL 測試

    $ curl localhost:8080
    Hello World: dev

如何透過 Maven、命令列參數、環境變數、.env 傳入屬性值

有些時候我們想透過 Maven 在應用程式的「編譯時期」加入屬性值,此時就會需要一個方法將 Maven 的?pom.xml?定義的屬性傳入到?src/main/resources/application.properties?屬性檔中。

體驗的步驟如下:

  1. 編輯?src/main/resources/application.properties?屬性檔

    加入一個?my.profile?屬性值

    my.profile=@my.profile@
  2. 調整?pom.xml?檔,在?<properties>?加入一個?<my.profile>?屬性

    <my.profile>dev2</my.profile>
  3. 測試執行

    mvn clean spring-boot:run

    使用 cURL 測試

    $ curl localhost:8080
    Hello World: dev2

我們在?application.properties?屬性檔中的?@my.profile@?語法非常特別,他會宣告你將從?外部?讀取屬性值,如果 Maven 有定義屬性的話,預設會在編譯專案時加入成為預設值。不過,這種語法還有一個優點,那就是可以讓你在?執行時期?才透過各種方法?賦值?(Assign Value)。例如:

  • 直接從?命令列參數?傳入參數

    mvn clean spring-boot:run -Dmy.profile=dev3
    $ curl localhost:8080
    Hello World: dev3
  • 直接從?環境變數?傳入屬性值

    以下是 Bash 設定環境變數的語法:

    my_profile=dev4 mvn clean spring-boot:run
    $ curl localhost:8080
    Hello World: dev4

    環境變數遇到屬性名稱有小數點(?.?)的時候,記得轉成底線(?_?)才可以。

  • 先封裝成 JAR 檔,透過?java -jar?執行時也可以透過?命令列參數?傳入參數

    mvn clean package
    java -Dmy.profile=dev5 -jar target/sbprofile1-0.0.1-SNAPSHOT.jar

    這個?-Dmy.profile=dev5?參數會傳入 JVM 當成系統參數使用。

    $ curl localhost:8080
    Hello World: dev5

    請記得?-Dmy.profile=dev5?一定要設定在?-jar?前面!

  • 先封裝成 JAR 檔,透過?java -jar?執行時也可以透過?環境變數?傳入參數

    mvn clean package
    my_profile=dev6 java -jar target/sbprofile1-0.0.1-SNAPSHOT.jar
    $ curl localhost:8080
    Hello World: dev6

    請記得?-Dmy.profile=dev5?一定要設定在?-jar?前面!

  • 直接從?.env?檔案定義的?環境變數?傳入參數

    先在專案根目錄加入一個?.env?檔,內容如下:

    my_profile=dev7

    建立一個?.vscode/launch.json?啟動設定檔 (VSCode)

    {
        "version": "0.2.0",
        "configurations": [
            {
                "type": "java",
                "name": "Launch DemoApplication",
                "request": "launch",
                "mainClass": "com.duotify.sbprofile1.DemoApplication",
                "projectName": "sbprofile1",
                "envFile": "${workspaceFolder}/.env"
            }
        ]
    }

    這裡的重點在於?envFile?設定。

    按下?F5?啟動專案,就可以讀到設定值了!

    $ curl localhost:8080
    Hello World: dev7

理解 Spring Profiles 設定檔的使用方式

在瞭解了 Properties 檔的使用與設定方式後,終於可以進入本文的重點內容,那就是如何定義 Spring Profiles 設定檔。

以下是體驗步驟:

  1. 編輯?src/main/resources/application.properties?屬性檔

    加入一個?spring.profiles.active?屬性值

    spring.profiles.active=@spring.profiles.active@

    這裡左邊的?spring.profiles.active?是 Spring 框架會使用的屬性名稱,而右邊的?@spring.profiles.active@?則是一個可以從?外部?傳入的屬性。

  2. 調整 Maven 的?pom.xml?設定檔,加入?<profiles>?區段設定

    <profiles>
      <profile>
        <id>default</id>
        <activation>
          <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
          <spring.profiles.active>default</spring.profiles.active>
        </properties>
      </profile>
      <profile>
        <id>dev8</id>
        <properties>
          <spring.profiles.active>dev8</spring.profiles.active>
        </properties>
      </profile>
    </profiles>

    這段設定比較特別的地方在於,我們定義了?2?份 Profiles,一個是我們的?default?設定檔,另一個則是?dev8?設定檔。然而不同的?設定檔?各有定義一個特別的?spring.profiles.active?屬性 (你也可以定義多個屬性),這個屬性專門是用來給 Spring 應用程式參考?目前啟用的設定檔?是誰。

    請記得: 你在?pom.xml?定義的屬性(?<properties>?)並不會直接給 Java 程式參考,他們之間的關係是:

    Java 原始檔 <-- 應用程式屬性檔(.properties/.yml) <-- 外部傳入屬性 (Maven 屬性 / 環境變數 / 命令列參數)
  3. 修改?HomeController?的?@Value?標注,改注入?spring.profiles.active?屬性

    package com.duotify.sbprofile1.controllers;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HomeController {
    
        @Value("${spring.profiles.active}")
        private String myProfile;
    
        @GetMapping("/")
        public String home() {
            return "Hello World: " + this.myProfile;
        }
    }
  4. 測試執行

    請記得我們現在有兩個設定檔,分別是?default?與?dev8?這兩個。當我們用?mvn spring-boot:run?啟動應用程式時,就可以用?-P?外加一個?ProfileName?就可以啟用設定檔。

    mvn clean spring-boot:run -Pdev8

    注意: 這裡的?-P?的?P?必須用字母大寫,而且後面接上的名稱是?pom.xml?當中的?<id>?元素值!

    使用 cURL 測試

    $ curl localhost:8080
    Hello World: dev8

    如果嘗試傳入一個?不存在的?dev9?設定檔名稱,將會得到預設的設定檔:

    mvn clean spring-boot:run -Pdev9
    $ curl localhost:8080
    Hello World: default

注意: 同時要啟用兩個 Profiles 是可以的,透過?-P?搭配逗號分隔即可。例如你可以用以下命令來測試啟用的 Profile 名稱:?mvn help:active-profiles -Pdev,prod

透過 Spring Profiles 切換不同的應用程式屬性檔

使用 Spring 框架的 Profiles 功能,有另外一個好處,那就是你可以不用把屬性都設定在 Maven 的?pom.xml?檔裡面,而是可以透過一種特殊的命名習慣,將應用程式屬性設定在不同的?.properties?檔案中。以下檔名規格請見註解說明:

# 這是預設的應用程式屬性檔,無論啟用哪一個設定,都會載入這個檔案中的屬性
application.properties

# 這是特定設定檔會套用的應用程式屬性檔,只有啟用的屬性檔會載入檔案中的屬性
application-{ProfileName}.properties

請注意: 在?application?檔名後面要接上?-?(dash) 符號,然後才是接上你的?ProfileName?才是正確的命名規則。

接著我們就來體驗一下多?設定檔?的套用情況:

  1. 我們再加入一個?dev9?設定檔到?pom.xml?檔中

    <profiles>
      <profile>
        <id>default</id>
        <activation>
          <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
          <spring.profiles.active>default</spring.profiles.active>
        </properties>
      </profile>
      <profile>
        <id>dev8</id>
        <properties>
          <spring.profiles.active>dev8</spring.profiles.active>
        </properties>
      </profile>
      <profile>
        <id>dev9</id>
        <properties>
          <spring.profiles.active>dev9</spring.profiles.active>
        </properties>
      </profile>
    </profiles>
  2. 除了?application.properties?之外,我們額外建立兩個應用程式屬性檔

    檔案 1:?src/main/resources/application.properties?(加入一個?my.name?屬性)

    my.profile=@my.profile@
    spring.profiles.active=@spring.profiles.active@
    my.name=Will

    檔案 2:?src/main/resources/application-dev8.properties?(加入一個?my.name?屬性)

    my.name=John

    檔案 3:?src/main/resources/application-dev9.properties?(空白內容)

  3. 修改?HomeController?的?@Value?標注,改注入?spring.profiles.active?屬性

    package com.duotify.sbprofile1.controllers;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HomeController {
    
        @Value("${spring.profiles.active}")
        private String myProfile;
    
        @Value("${my.name}")
        private String myName;
    
        @GetMapping("/")
        public String home() {
            return "Hello World: " + this.myName;
        }
    }
  4. 測試執行

    請記得我們現在有?3?個設定檔,分別是?default?,?dev8?與?dev9?這三個。

    先嘗試不指定 Profile 的情況

    mvn clean spring-boot:run
    $ curl localhost:8080
    Hello World: Will

    再嘗試指定 Profile?dev8?的情況

    mvn clean spring-boot:run -Pdev8
    $ curl localhost:8080
    Hello World: John

    最後嘗試指定 Profile?dev9?的情況

    mvn clean spring-boot:run -Pdev9
    $ curl localhost:8080
    Hello World: Will

透過 Spring Profiles 載入不同的相依套件

透過 Spring Profiles 設定檔的方式進行組態設定,除了可以設定「屬性」之外,還能依據不同?設定檔?(Profile)來載入不同的?<dependencies>?相依套件,例如載入?相同套件?的?不同版本?(測試新舊版本),或是?相同介面?但?不同套件?(不同資料庫驅動程式)之類的,這點真的很讚! :+1:

  • 以下是?相同套件不同版本?的設定範例:

    <profile>
      <id>dev8</id>
      <dependencies>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
          <version>2.7.0</version>
        </dependency>
      </dependencies>
      <properties>
        <spring.profiles.active>dev8</spring.profiles.active>
      </properties>
    </profile>

    如果想看套用不同 Profile 之後的相依套件資訊,可以執行以下命令:

    mvn dependency:tree -Pdev8
  • 以下是?相同介面不同套件?的設定範例:

    <profiles>
      <profile>
        <id>Local</id>
        <dependencies>
          <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>2.3.3</version>
            <classifier>jdk5</classifier>
          </dependency>
        </dependencies>
        <properties>
          <jdbc.url>jdbc:hsqldb:file:databaseName</jdbc.url>
          <jdbc.username>a</jdbc.username>
          <jdbc.password></jdbc.password>
          <jdbc.driver>org.hsqldb.jdbcDriver</jdbc.driver>
        </properties>
      </profile>
      <profile>
        <id>MySQL</id>
        <dependencies>
          <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
          </dependency>
        </dependencies>
        <properties>
          <jdbc.url>jdbc:mysql://mysql.website.ac.uk:3306</jdbc.url>
          <jdbc.username>user</jdbc.username>
          <jdbc.password>1234</jdbc.password>
          <jdbc.driver>com.mysql.jdbc.Driver</jdbc.driver>
        </properties>
      </profile>
    </profiles>

透過 Spring Profiles 載入不同 Beans 元件

在 Spring 框架下,所有套用?@Component?標注的類別全部都會被註冊成 Beans 元件,其中當然也包含套用?@Configuration?標注的類別,因為這些標注都繼承自?@Component?介面。

然而,你只要很簡單的在類別上額外套用?@Profile?標注,就可以宣告 Spring 要在特定 Profile 下載入,以下是使用範例:

  1. 建立一個?UserService?類別

    package com.duotify.sbprofile1.services;
    
    public class UserService {
        public UserService(String name) {
            this.name = name;
        }
        private String name;
        public String getName() {
            return name;
        }
    }
  2. 建立一個?UserServiceDev?類別

    package com.duotify.sbprofile1.services;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Profile;
    import org.springframework.stereotype.Component;
    
    @Component
    @Profile("dev")
    public class UserServiceDev {
        @Bean
        public UserService getUserService() {
            return new UserService("Dev");
        }
    }

    這個?UserServiceDev?只有在啟用?dev?設定檔時才會被 Spring 執行。

  3. 建立一個?UserServiceProd?類別

    package com.duotify.sbprofile1.services;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Profile;
    import org.springframework.stereotype.Component;
    
    @Component
    @Profile("!dev")
    public class UserServiceProd {
        @Bean
        public UserService getUserService() {
            return new UserService("Prod");
        }
    }

    這個?UserServiceDev?只有在啟用 non-?dev?設定檔時才會被 Spring 執行。

  4. 修改?HomeController?並透過「建構式」注入?UserService?服務

    package com.duotify.sbprofile1.controllers;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.duotify.sbprofile1.services.UserService;
    
    @RestController
    public class HomeController {
    
        @Value("${spring.profiles.active}")
        private String myProfile;
    
        @Value("${my.name}")
        private String myName;
    
        private UserService svc;
    
        public HomeController(UserService svc) {
            this.svc = svc;
        }
    
        @GetMapping("/")
        public String home() {
            return "Hello World: " + this.svc.getName();
        }
    }
  5. 修改?pom.xml?再加入兩個?<profile>?定義

    <profile>
      <id>dev</id>
      <properties>
        <spring.profiles.active>dev</spring.profiles.active>
      </properties>
    </profile>
    <profile>
      <id>prod</id>
      <properties>
        <spring.profiles.active>prod</spring.profiles.active>
      </properties>
    </profile>
  6. 測試執行

    請記得我們現在有?5?個設定檔,分別是?default?,?dev8?,?dev9?,?dev?與?prod?這五個。

    嘗試指定 Profile?dev?的情況

    mvn clean spring-boot:run -Pdev
    $ curl localhost:8080
    Hello World: Dev

    嘗試指定 Profile?prod?的情況

    mvn clean spring-boot:run -Pprod
    $ curl localhost:8080
    Hello World: Prod

    ?

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-09-24 20:42:44  更:2022-09-24 20:43:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 9:24:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码