Maven profile整合Spring profile

在Maven和Spring中,都有profile這個概念。profile是用於區分各種環境的,例如開發環境、測試環境、正式環境等。Maven的profile用於在打包時根據指定環境替換不同環境的配置文件配置,如數據庫配置。Spring的Profile可以用於在不同的環境下加載不同的bean,例如@Profile註解。兩者一個是Maven編譯和打包時生效,另一個是運行時生效,默認是沒有關聯的,本文會分別介紹非Spring Boot項目和Spring Boot項目整合Maven profile。

Maven profile配置

pom.xml中,可以配置testproduct兩個profile,分別對應測試環境和正式環境。這裏也可以根據具體情況自定義。

<profiles>
  <profile>
    <id>test</id>
    ...
  </profile>
  <profile>
    <id>product</id>
    ...
  </profile>
</profiles>

此時,運行mvn package -Ptest就會使用id爲test的profile內的配置打包,mvn package -Pproduct就是用來打正式環境包的命令。

Spring Framework(非Spring Boot)整合Maven profile

Spring Framework如何啓用一個profile

Spring啓用某個profile有多種方式(摘自官方文檔:https://docs.spring.io/spring... ):

Activating a profile can be done in several ways, but the most straightforward is to do it programmatically against the Environment API which is available through an ApplicationContext.
In addition, you can also declaratively activate profiles through the spring.profiles.active property, which may be specified through system environment variables, JVM system properties, servlet context parameters in web.xml, or even as an entry in JNDI.

總結一下有以下幾種方式:

  • 通過代碼設置:ApplicationContext.getEnvironment().setActiveProfiles("yourProfile")
  • 通過系統環境變量spring.profiles.active值來設置
  • 通過JVM系統屬性spring.profiles.active值來設置
  • 通過web.xml中的context-param來設置

爲了便於跟Maven整合,我們使用web.xml來設置Spring profile,如下:

<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>product</param-value>
</context-param>

以上配置會啓用Spring的product profile,即正式環境。

Spring Framework profile整合Maven profile

如果想要整合Maven profile和Spring Framework profile,需要在Maven打包時對web.xml中的spring.profiles.active值進行替換,可以在web.xml中配置一個佔位符${activeProfile}

<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>${activeProfile}</param-value>
</context-param>

pom.xml配置maven-war-plugin

<!-- 打war包時替換佔位符 -->
<build>
  <plugin>
    <artifactId>maven-war-plugin</artifactId>
    <version>3.2.2</version>
    <configuration>
      <filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
    </configuration>
  </plugin>
</build>

<!-- 默認的maven profile -->
<properties>
  <activeProfile>dev</activeProfile>
</properties>

<profiles>
  <profile>
    <id>test</id>
    <properties>
      <activeProfile>test</activeProfile>
    </properties>
  </profile>
  <profile>
    <id>product</id>
    <properties>
      <activeProfile>product</activeProfile>
    </properties>
  </profile>
</profiles>

<filteringDeploymentDescriptors>true表示過濾Deployment Descriptor並將文件中的佔位符替換爲pom.xml中對應的<properties>值,Deployment Descriptor即部署描述符,指的就是web.xml (參考維基百科:https://zh.wikipedia.org/wiki... )。

以上配置完成後,再通過mvn package -Ptestmvn package -Pproduct打包後,再解壓war包,可以看到web.xml中原有的

<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>${activeProfile}</param-value>
</context-param>

被替換爲了Maven中對應的profile,例如mvn package -Pproduct打包後web.xml內容:

<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>product</param-value>
</context-param>

以上就完成了Maven profile和Spring profile的整合。

兼容jetty-maven-plugin

如果恰好在項目中使用到jetty-maven-plugin用於開發環境調試,那麼在web.xml配置佔位符${activeProfile}後,通過mvn jetty:run啓動應用時會Spring框架會報錯:

Could not resolve placeholder 'activeProfile' in string value "${activeProfile}"

這是因爲運行mvn jetty:run命令時插件並沒有打war包,而是直接使用源碼中的web.xml,此時佔位符${activeProfile}未被maven-war-plugin替換,所以Spring框架會報錯。

參考文檔:https://www.eclipse.org/jetty...

解決方法一

使用mvn jetty:run-warmvn jetty:run-exploded命令替代mvn jetty:run,這兩個命令會先用maven-war-plugin打好war包後再運行,此時佔位符${activeProfile}已被替換爲Maven的profile。

但是這種方案會帶來一個問題:由於這種方式需要先打war包再運行,開發時項目中資源(例如html、jsp)修改後就不會實時生效,而是需要重新打包啓動,不便於調試。

解決方法二(推薦)

這種方案還是使用mvn jetty:run命令,只需要給jetty-maven-plugin插件添加一個名爲activeProfile的系統屬性,讓Spring框架來解析web.xml中的${activeProfile}

<plugin>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-maven-plugin</artifactId>
  <version>9.2.10.v20150310</version>
  <configuration>
    <webApp>
      <contextPath>/</contextPath>
    </webApp>
    <systemProperties>
      <systemProperty>
        <name>activeProfile</name>
        <value>${activeProfile}</value>
      </systemProperty>
    </systemProperties>
  </configuration>
</plugin>

參考文檔:https://www.eclipse.org/jetty...

Spring Boot整合Maven profile

如果項目採用的框架是Spring Boot而不是直接使用Spring Framework,那麼Spring Boot的profile可以在resources目錄下的application.propertiesapplication.yml文件中指定,以application.properties爲例:

spring.profiles.active=product

要想整合Maven profile只需要改爲@activeProfile@佔位符即可:

spring.profiles.active=@activeProfile@

僅需要這一行配置就完成了Spring Boot profile整合Maven profile,非常方便。此時可以嘗試mvn package -Ptestmvn package -Pproduct命令打包,安裝包內的文件中@activeProfile@佔位符已被替換。

Spring Boot整合Maven profile原理

Spring Boot項目中一般都會加上spring-boot-starter-parent

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>${spring.boot.version}</version>
</parent>

可以查看spring-boot-starter-parent的pom.xml文件,裏面包含maven-resources-plugin

<plugin>
    <artifactId>maven-resources-plugin</artifactId>
    <configuration>
        <delimiters>
            <delimiter>${resource.delimiter}</delimiter>
        </delimiters>
        <useDefaultDelimiters>false</useDefaultDelimiters>
    </configuration>
</plugin>

${resource.delimiter}定義的值是@

<resource.delimiter>@</resource.delimiter>

這樣maven-resources-plugin插件會將application.propertiesapplication.yml文件中的@activeProfile@替換爲pom.xml中對應profile的值。

至於爲什麼Spring Boot要使用@..@而不是Maven默認的${..}作爲佔位符的符號,官方文檔也給出瞭解釋,以下摘自:https://docs.spring.io/spring...

Note that, since the application.properties and application.yml files accept Spring style placeholders (${…​}), the Maven filtering is changed to use @..@ placeholders. (You can override that by setting a Maven property called resource.delimiter.)

因爲Spring Boot框架本身也用${..}作爲佔位符,Maven插件maven-resources-plugin如果還使用相同的佔位符,那麼可能會導致一些衝突,所以spring-boot-starter-parentmaven-resources-plugin的佔位符改爲@..@

參考文檔

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