1. 程式人生 > >Maven 整合 spring profile實現多環境自動切換

Maven 整合 spring profile實現多環境自動切換

profile主要用在專案多環境執行的情況下,比如開發環境、測試環境、線上生產環境。
我負責的專案某個資料管理後臺涉及到包含測試環境在內的12個不同的執行環境,所以每次釋出都很蛋疼很糾結,配置改過來改過去,到最後有些環境都忘了怎麼配的。
下面以這個專案為例介紹。
準備條件:spring3.x、Maven 2

這裡是整合spring的profile和Maven的profile功能

[b][size=large]spring的profile配置[/size][/b]

首先是spring的配置資料來源和屬性檔案

<beans profile="xmj_old">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://127.0.0.1:3306/db1?characterEncoding=utf8" />
<property name="password" value="123456" />
<property name="username" value="abc" />
</bean>
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:messages_zh_CN</value>
<value>classpath:messages/messages_en_US-xmj_old</value>
</list>
</property>
</bean>
</beans>
<beans profile="xmj_new">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://127.0.0.1:3306/db1?characterEncoding=utf8" />
<property name="password" value="123456" />
<property name="username" value="abc" />
</bean>
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:messages_zh_CN</value>
<value>classpath:messages/messages_en_US-xmj_new</value>
</list>
</property>
</bean>
</beans>
...
...
...


這裡的message_en_US-*系列屬性檔案是配置站點的名稱和黑名單的位置:

resource.blacklist.dir=/var/resource/blacklist.txt
system.title.id=system.xmj_old.title


[b][size=large]啟用spring的profile[/size][/b]

profile是配置完了,但還要啟用spring的profile特性。
在web.xml做如下配置:


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


這樣就啟用spring配置檔案中的profile為xmj_old的配置,但這樣手動配置依然要改web.xml配置。
Maven也帶了profile的功能,而且我們的專案一般都是由Maven管理的,下面介紹Maven配置profile。

[b][size=large]Maven 配置profile[/size][/b]
Maven配置profile也很簡單,舉例如下:

<profiles>
<profile>
<id>xmj_old</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<profiles.activation>xmj_old</profiles.activation>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<!-- 配置專案自動釋出伺服器 -->
<url>http://xx.xx.xx.xx:8080/manager/text</url>
<path>/xmj-manager</path>
<server>Tomcat</server>
<warFile>target/${profiles.activation}.war</warFile>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>xmj_new</id>
<properties>
<profiles.activation>xmj_new</profiles.activation>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<!-- 配置專案自動釋出伺服器 -->
<url>http://xx2.xx.xx.xx:8080/manager/text</url>
<path>/xmj-manager</path>
<server>Tomcat</server>
<warFile>target/${profiles.activation}.war</warFile>
</configuration>
</plugin>
</plugins>
</build>
</profile>
...
...
...
</profiles>


activeByDefault標籤配置true表示預設啟用的環境,直接install就是使用此配置的環境。
這裡有一個自定義屬性配置:profiles.activation 它就是整合Maven profile 和spring profile 的重要配置

[b][size=large]整合Maven profile 和spring profile[/size][/b]

通過Maven管理web實現自動化,少改動就少出錯,將上面web.xml配置改為下面的:

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


這還不算完,還要配置Maven的一個外掛:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warName>${profiles.activation}</warName>
<!-- 啟用spring profile -->
<webResources>
<resource>
<filtering>true</filtering>
<directory>src/main/webapp</directory>
<includes>
<include>**/web.xml</include>
</includes>
</resource>
</webResources>
<warSourceDirectory>src/main/webapp</warSourceDirectory>
<webXml>src/main/webapp/WEB-INF/web.xml</webXml>
</configuration>
</plugin>


打包的時候Maven會去自動修改web.xml檔案,根據佔位符自動替換為對應的屬性值
warName標籤可以不配置,我這裡加上了所以需要加上前面的target/${profiles.activation}.war,否則會報找不到war包的異常。

執行profile
下面是見證奇蹟的時刻
在eclipse中執行命令:

clean install

前面配置的預設環境是xmj_old這個,在執行完命令之後target資料夾下面出現了一個名為xmj_old.war的war包

[img]http://dl2.iteye.com/upload/attachment/0094/9770/fbe5cfbb-fbb6-392b-8fec-415627ed8eab.jpg[/img]

開啟war包檢視web.xml

[img]http://dl2.iteye.com/upload/attachment/0094/9772/9f1d416e-c85d-39d9-be89-da78d9c33e38.jpg[/img]

再測試下切換到其他的環境
執行命令

clean install -P xmj_new

-P 引數後面加上profile的id即可完成自動切換,執行完之後看下是否已經自動切換到id為xmj_new的profile環境下
target檔案下有了xmj_new.war的war包(xmj_old.war被clean掉了)

[img]http://dl2.iteye.com/upload/attachment/0094/9766/74a80b15-588c-3d5d-be27-5834be22ba80.jpg[/img]

開啟war包檢視web.xml檔案

[img]http://dl2.iteye.com/upload/attachment/0094/9768/9f61ae13-d451-3ed9-aba0-37280b4827d1.jpg[/img]

如預期所料,Maven結合spring成功的完成了多環境的自動切換
注:上面web.xml中的display-name和webAppRootKey都是使用佔位符${profiles.activation}然後Maven自動替換的,如果你的專案中使用log4j/logback和spring,然後同一個專案部署多個例項到一個tomcat中,建議配置webAppRootKey這個引數
請參考 [url=http://zilongsky-gmail-com.iteye.com/blog/2032070]log4j/logback + spring的webRootKey bug[/url]

[b][size=large]在本地eclipse內建tomcat中執行[/size][/b]

由於內建tomcat是直接編譯原始碼然後放到指定的位置去載入
所以上述的方法對於在內建tomcat執行是行不通的,在本地測試就非常蛋疼了
網上說有設定專案屬性中Maven的profile,查了下eclipse官網說是由於m2eclipse有bug的問題,這個配置已經給禁用了
那就要另覓他法了,下面介紹一種探索出的一個方法:

首先在main目錄下新建一個profile資料夾,將WEB-INF下面的web.xml複製過來一份
然後將WEB-INF下面的web.xml中的佔位符修改成預設的配置(即沒有佔位符的,在本地測試用的profile值)
profile資料夾下保留佔位符的web.xml配置

[img]http://dl2.iteye.com/upload/attachment/0094/9764/0bc370ae-6534-38e4-ab92-824bebb70ffc.jpg[/img]

下面是WEB-INF下面沒有佔位符的正常的配置

[img]http://dl2.iteye.com/upload/attachment/0094/9762/f200cf90-f828-3840-adfc-24395bf84be2.jpg[/img]

這些佔位符我都換成了ysxj
接下來修改Maven配置
將配置:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warName>${profiles.activation}</warName>
<!-- 啟用spring profile -->
<webResources>
<resource>
<filtering>true</filtering>
<directory>src/main/webapp</directory>
<includes>
<include>**/web.xml</include>
</includes>
</resource>
</webResources>
<warSourceDirectory>src/main/webapp</warSourceDirectory>
<webXml>src/main/webapp/WEB-INF/web.xml</webXml>
</configuration>
</plugin>

修改為:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warName>${profiles.activation}</warName>
<!-- 啟用spring profile -->
<webResources>
<resource>
<filtering>true</filtering>
<!-- 這裡是剛剛建立的目錄 -->
<directory>src/main/profile</directory>
<!-- 目標目錄為WEB-INF -->
<targetPath>WEB-INF</targetPath>
<includes>
<include>**/web.xml</include>
</includes>
</resource>
</webResources>
<warSourceDirectory>src/main/webapp</warSourceDirectory>
<webXml>src/main/webapp/WEB-INF/web.xml</webXml>
</configuration>
</plugin>

最後見證奇蹟
執行命令

install -P naruto

在target下面出現根據profile打的war包naruto.war
接下來證明可以在eclipse的內建tomcat使用
執行命令

eclipse:eclipse -Dwtpversion=1.5

編譯成正常的eclipse工程,然後加入tomcat伺服器,你會發現能執行成功。
這裡tomcat使用的是原始碼中WEB-INF下的web.xml,即剛才將佔位符修改為ysxj的那個web.xml
其原理就是在編譯階段將profile資料夾下的web.xml中的佔位符替換成Maven中配置的屬性,然後覆蓋WEB-INF下面的web.xml
這種方法麻煩的一點就是如果web.xml檔案有修改 ,兩個記得要同步,一般情況下這個檔案也極少動

ps. 騷年們不要手動了,來玩自動的吧