1. 程式人生 > 實用技巧 >maven 多環境profile載入不同配置檔案自由切換

maven 多環境profile載入不同配置檔案自由切換

1.情景展示

  在實際開發過程中,我們經常會有這樣需求:

  開發環境或測試環境,使用測試資料庫;生產環境使用正式資料庫。

  日誌級別、引用的jar包、打包方式有時也會不一樣,這樣,同一專案就會存在多個執行環境。

  對於初學者而言,通常的做法就是:

  開發的時候在配置檔案使用相關配置資訊;需要部署專案的時候,再將原有程式碼註釋掉,重新配置一套環境;打完包,在本地除錯的時候,再將生產環境配置登出掉,還原開發環境。

  首先,這種方法肯定能是可行的,但經常改來改去,不便維護及拓展。

  下面,介紹一種更好的方案。

2.環境分析

  我們先來了解一下,環境的種類有哪些?

  • 開發環境:development,通常用dev表示;
  • 測試環境:test,通常使用test表示;
  • 預演環境:preview,通常使用prev表示,相當於試執行階段,處於測試和正式階段之間;
  • 生產環境:production,通常使用prod表示。

  基本上上面的4種環境,就涵蓋了我們研發一種產品的所有階段。

  這裡,需要說明的是:環境的名稱是可以自定義的,你可以定義成任何名稱,只不過是上面4種是大家約定俗稱的名字而已,無論是誰看到,就能立馬明白什麼意思;而如果你將名字定義成aa,也許只有你自己知道它代表的是哪個環境了。

  下面,我先講一種大眾化的多環境開發模式。

  第一,application.properties/yml,作為spring的主配置檔案。

  由該配置檔案來決定,哪個配置檔案生效。

  通過spring.profiles.active來設定生效的配置檔案,如上圖所示,我使用的是dev,在啟動專案時,spring會載入application-dev.properties

  第二,設定環境配置檔案

  這種方式,很簡單,容易上手,沒什麼好說的。

3.解決方案

  這裡,介紹一種更為高階的使用方式。

  通過pom.xml的profile標籤來管理環境,換句話說就是:使用maven來完成環境的管理,在使用maven命令進行打包時實現。

  打包形式、打包時是否跳過測試階段、是否啟用介面說明文件、日誌級別、以及引用的jar包,通通由profile來管理,實現在多環境中共存。

  先來看看pom.xml的構成吧,關鍵程式碼展示:

<groupId>com.公司簡稱</groupId>
<artifactId>專案名稱</artifactId>
<!--打包形式:通過maven的profile來決定打成war包還是打jar包(如果不配置packaging標籤的話,預設值是jar)-->
<packaging>${project.packaging}</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>專案名稱</name>
<description>專案簡述</description>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.1.RELEASE</version>
</parent>

<properties>
    <!--指定tomcat內建版本(只對springboot內建tomcat生效)-->
    <!--<tomcat.version>8.5.0</tomcat.version>-->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <!--java版本-->
    <java.version>1.8</java.version>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <!--proguard版本-->
    <proguard.version>6.2.2</proguard.version>
    <!--spring版本號-->
    <spring.version>2.3.1.RELEASE</spring.version>
    <!--打包時是否跳過測試階段(使用profile來指定打包時是否進行測試)-->
    <skipTests>${skipTests}</skipTests>

    <!--載入application-*.yml配置檔案(通過該標籤來指定即將生效的配置檔案)-->
    <!--載入application-test.yml配置檔案(profile需要勾選成test)-->
    <spring.profiles.active>test</spring.profiles.active>
    <!--基層(測試環境)-->
    <!--<spring.profiles.active>jc</spring.profiles.active>-->

    <!--載入application-prod.yml配置檔案-->
    <!--這樣,這裡就可以根據實際需要,進行多個生產環境間的切換(profile需要勾選成prod)-->
    <!--基層(正式環境)-->
    <!--<spring.profiles.active>jc</spring.profiles.active>-->
</properties>

<!--根據不同的環境引用不同的jar包,最終統一打包到專案當中-->
<!--生產環境:prod,開發環境:dev,測試環境:test,預演環境:prev
使用maven命令打包介紹:
開發環境打包:mvn clean package -Dmaven.test.skip=true -P dev
測試環境打包:mvn clean package -Dmaven.test.skip=true -P test
生產環境打包:mvn clean package -Dmaven.test.skip=true -P prod
!!!另外,在idea中切換生產環境和開發環境時,需要重新導包!!!-->
<profiles>
    <!--開發環境-->
    <profile>
        <id>dev</id>
        <activation>
            <!-- 預設啟用本環境 -->
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <!--載入application-dev.yml配置檔案(profile需要勾選成dev)-->
            <spring.profiles.active>dev</spring.profiles.active>
            <!--environment這個節點是我自己取的:yml檔案根據該標籤的值來確定介面地址是正式地址還是測試地址-->
            <environment>development</environment>
            <!--是否是生產環境:通過配置該值,來決定是否啟用knife4j-->
            <isProduction>false</isProduction>
            <!--日誌級別-->
            <logLevel>DEBUG</logLevel>
            <!--打包方式:
                設定成jar包時,在idea中,不能通過外掛的package進行打包,
                只能通過命令來實現:mvn clean package -Dmaven.test.skip=true -P dev
            -->
            <project.packaging>jar</project.packaging>
            <!--打包時,需要進行測試-->
            <skipTests>true</skipTests>
        </properties>
        <dependencies>
            <!--jsp不能夠在jar中使用,只能夠在War中使用
            所以,如果確定部署專案的時候以jar的形式執行的話,則專案就不能使用jsp了,
            因為,maven在執行打包命令時,jsp是不會被打包到jar包當中的-->
            <!-- 使用jsp引擎,springboot內建tomcat沒有此依賴 -->
            <dependency>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-jasper</artifactId>
                <version>9.0.36</version>
            </dependency>
            <!--增加對 JSP 檔案的支援-->
            <dependency>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat-jsp-api</artifactId>
                <version>9.0.36</version>
            </dependency>
            <!-- 新增jstl標籤庫依賴模組 -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
                <version>1.2</version>
            </dependency>
        </dependencies>
    </profile>
    <!--測試環境-->
    <profile>
        <id>test</id>
        <activation>
            <activeByDefault>false</activeByDefault>
        </activation>
        <properties>
            <environment>test</environment>
            <isProduction>false</isProduction>
            <logLevel>INFO</logLevel>
            <project.packaging>war</project.packaging>
            <skipTests>true</skipTests>
        </properties>
        <dependencies>
           <!--引用的jar包與生產環境一樣,這裡不再展示-->
        </dependencies>
    </profile>
    <!--預演環境-->
    <profile>
        <id>prev</id>
        <activation>
            <activeByDefault>false</activeByDefault>
        </activation>
        <properties>
            <environment>preview</environment>
            <isProduction>true</isProduction>
            <logLevel>INFO</logLevel>
            <project.packaging>war</project.packaging>
            <skipTests>true</skipTests>
        </properties>
        <dependencies>
           <!--引用的jar包與生產環境一樣,這裡不再展示-->
        </dependencies>
    </profile>
    <!--生產環境-->
    <!--在本地通過Application啟動專案時,其本質還是使用的springboot的內建tomcat,由於內建tomcat不支援使用jsp,
    所以,此時是無法訪問專案對應的jsp頁面的,
    只有將其部署在tomcat上並啟動SpringBootStartApplication才能正常訪問-->
    <profile>
        <id>prod</id>
        <!-- 是否啟用本環境 -->
        <activation>
            <activeByDefault>false</activeByDefault>
        </activation>
        <properties>
            <environment>production</environment>
            <isProduction>true</isProduction>
            <logLevel>ERROR</logLevel>
            <project.packaging>war</project.packaging>
            <!--打包時,跳過測試階段(因為測試階段會去連線資料庫,正式資料庫本地無法訪問,會導致打包失敗)-->
            <skipTests>true</skipTests>
        </properties>
        <!--專案中,編譯和測試階段用到的jar包,但tomcat中存在這些jar包,此時,在部署到tomcat中時,我們就需要把它們踢掉-->
        <dependencies>
            <!--內建tomcat(剔除該jar包)-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
                <!--只有編譯和測試階段生效-->
                <scope>provided</scope>
            </dependency>
            <!-- servlet依賴(只在開發時使用,因為部署到tomcat上時,tomcat有對應的jar包) -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <scope>provided</scope>
            </dependency>
            <!-- jstl標籤庫依賴 -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
                <version>1.2</version>
                <scope>provided</scope>
            </dependency>
        </dependencies>
    </profile>
</profiles>
<!--配置專案的jar包倉庫-->
<repositories>
    <!--阿里雲倉庫-->
    <repository>
        <id>central</id>
        <name>central maven</name>
        <url>https://maven.aliyun.com/repository/central</url>
        <!--<url>http://maven.aliyun.com/nexus/content/groups/public/</url>-->
    </repository>
    <!--maven官網-->
    <repository>
        <id>public</id>
        <name>public maven</name>
        <url>https://mvnrepository.com</url>
    </repository>
</repositories>
<!--jar包依賴-->
<dependencies>
    <!--公共類封裝引用-->
    <dependency>
        <groupId>code.marydon.encapsulation</groupId>
        <artifactId>javaUtils</artifactId>
        <version>1.0</version>
    </dependency>
</dependencies>

  再來看看application.yml主配置檔案

  這裡的關鍵點在於:

  yml檔案想要引用pom.xml中的property標籤的值時,在要引用的標籤名稱兩邊加上@,即:@propertyName@;如果是properties檔案想要引用,使用的是EL表示式,${propertyName}。

  這樣,就將啟用的配置檔案的決定權交給了pom.xml。

  提示:

  在idea中,按住Ctrl鍵不鬆手,會跳轉到對應pom.xml該標籤所處位置。

  knife4j配置(如果沒有,就忽略)

  實現的效果就是:開發環境和測試環境可以訪問介面文件,預演環境和生產環境禁止訪問。

  資料庫配置、日誌配置等自定義配置不在主配置檔案裡放,放到對應的環境配置檔案當中。

  假設,我們需要呼叫第三方的介面,而第三方介面也分測試地址和正式地址。

  那我們就可以在這裡使用自定義標籤,把正式介面和測試介面新增到配置檔案當中。

  如果沒有這種需求,就可以跳過。

  這樣,我們分別獲取到當前生效的是哪種環境,測試介面地址,正式介面地址,根據環境來決定最終呼叫哪個地址。

  這只是環境的一種使用方式,還有一種應用場景是:根據環境來控制控制層的是否可見(特定請求只在特定環境生效),下篇文章會講。

  最後,來看看日誌。

  日誌級別,也由pom.xml的profile標籤來決定。

  通常情況下,開發環境使用debug、測試環境使用info,生產環境使用error。

  每種環境的個性化需求,都可以通過這種方式來實現。

  如何正確使用多環境的切換?

  在idea中,想要專案完成環境的切換,至少需要完成前三步,一般專案在清空target目錄後,idea會完成自動編譯,如果沒有那就是你沒有設定自動編譯;

  在idea中,經常會出現因idea自帶的maven外掛因環境切換失敗導致專案編譯失敗的問題,這也沒有辦法,是idea自身的問題,重複上述步驟即可。

  原理就是:maven外掛會將yml檔案中引用的標籤的值寫入對應的配置檔案中。

  補充一點:

  如上圖所示,一個地方會產生一個配置檔案,而每個地方又可分為生產環境和測試環境,這時候,第一種方式就會顯得力不從心。

  現在,我們只需要三步即可:

  增加一個配置檔案,比如叫做:application-aa.yml;

  在pom.xml中,將原有的<spring.profiles.active>註釋掉,新增一個同樣的標籤<spring.profiles.active>aa</spring.profiles.active>;

  選擇要生效的環境,重新編譯專案即可。

  這樣,就實現了多區域多環境可以隨意切換的效果。

寫在最後

  哪位大佬如若發現文章存在紕漏之處或需要補充更多內容,歡迎留言!!!

相關推薦: