1.情景展示
聲明:本文和springboot沒有關系,本質是:maven與spring相互作用產生的效果,之所以標題使用它,是為了讓更多人看到。
在實際開發過程中,我們經常會有這樣需求:
開發環境或測試環境,使用測試數據庫;生產環境使用正式數據庫。
日志級別、引用的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>;
選擇要生效的環境,重新編譯項目即可。
這樣,就實現了多區域多環境可以隨意切換的效果。