接上回繼續,專案開發好以後,通常要在多個環境部署,象我們公司多達5種環境:本機環境(local)、(開發小組內自測的)開發環境(dev)、(提供給測試團隊的)測試環境(test)、預釋出環境(pre)、正式生產環境(prod),每種環境都有各自的配置引數,比如:資料庫連線、遠端呼叫的ws地址等等。如果每個環境build前手動修改這些引數,顯然太不fashion.
maven早就考慮到了這些問題,看下面的pom片段:
1 <profiles> 2 <profile> 3 <!-- 本地環境 --> 4 <id>local</id> 5 <properties> 6 <db-url>jdbc:oracle:thin:@localhost:1521:XE</db-url> 7 <db-username>***</db-username> 8 <db-password>***</db-password> 9 </properties> 10 </profile> 11 <profile> 12 <!-- 開發環境 --> 13 <id>dev</id> 14 <properties> 15 <db-url>jdbc:oracle:thin:@172.21.129.51:1521:orcl</db-url> 16 <db-username>***</db-username> 17 <db-password>***</db-password> 18 </properties> 19 <!-- 預設啟用本環境 --> 20 <activation> 21 <activeByDefault>true</activeByDefault> 22 </activation> 23 </profile> 24 ... 25 </profiles>
profiles節點中,定義了二種環境:local、dev(預設啟用dev環境),可以在各自的環境中新增需要的property值,接下來修改build節點,參考下面的示例:
1 <build> 2 <resources> 3 <resource> 4 <directory>src/main/resources</directory> 5 <filtering>true</filtering> 6 </resource> 7 </resources> 8 <plugins> 9 <plugin> 10 <groupId>org.apache.maven.plugins</groupId> 11 <artifactId>maven-compiler-plugin</artifactId> 12 <version>2.5.1</version> 13 <configuration> 14 <source>1.6</source> 15 <target>1.6</target> 16 <encoding>utf-8</encoding> 17 </configuration> 18 </plugin> 19 </plugins> 20 </build>
resource節點是關鍵,它表明了哪個目錄下的配置檔案(不管是xml配置檔案,還是properties屬性檔案),需要根據profile環境來替換屬性值。
通常配置檔案放在resources目錄下,build時該目錄下的檔案都自動會copy到class目錄下
以上圖為例,其中spring-database.xml的內容為:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 7 <bean id="dataSource" 8 class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 9 <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> 10 <property name="url" value="${db-url}" /> 11 <property name="username" value="${db-username}" /> 12 <property name="password" value="${db-password}" /> 13 </bean> 14 </beans>
各屬性節點的值,用佔位符"${屬性名}"佔位,maven在package時,會根據profile的環境自動替換這些佔位符為實際屬性值。
預設情況下:
maven package
將採用預設啟用的profile環境來打包,也可以手動指定環境,比如:
maven package -P dev
將自動打包成dev環境的部署包(注:引數P為大寫)
最後再給2個例項的運用例子:
1、開發環境與生產環境資料來源採用不同方式的問題
本機開發時為了方便,很多開發人員喜歡直接用JDBC直接連線資料庫,這樣修改起來方便;
1 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 2 destroy-method="close"> 3 <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> 4 <property name="url" value="${db-url}" /> 5 <property name="username" value="${db-username}" /> 6 <property name="password" value="${db-password}" /> 7 <property name="defaultAutoCommit" value="false" /> 8 <property name="initialSize" value="2" /> 9 <property name="maxActive" value="10" /> 10 <property name="maxWait" value="60000" /> 11 </bean>
而生產環境,通常是在webserver(比如weblogic上)配置一個JNDI資料來源,
1 <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> 2 <property name="jndiName" value="appDS" /> 3 </bean>
如果每次釋出生產前,都要手動修改,未免太原始,可以通過maven的profile來解決
先把配置檔案改成
1 <bean id="${db-source-jdbc}" class="org.apache.commons.dbcp.BasicDataSource" 2 destroy-method="close"> 3 <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> 4 <property name="url" value="${db-url}" /> 5 <property name="username" value="${db-username}" /> 6 <property name="password" value="${db-password}" /> 7 <property name="defaultAutoCommit" value="false" /> 8 <property name="initialSize" value="2" /> 9 <property name="maxActive" value="10" /> 10 <property name="maxWait" value="60000" /> 11 </bean> 12 13 <bean id="${db-source-jndi}" class="org.springframework.jndi.JndiObjectFactoryBean"> 14 <property name="jndiName" value="appDS" /> 15 </bean>
即用佔位符來代替bean的id,然後在pom.xml裡類似下面設定
1 <profile> 2 <!-- 本機環境 --> 3 <id>local</id> 4 <properties> 5 ... 6 <db-source-jdbc>dataSource</db-source-jdbc> 7 <db-source-jndi>NONE</db-source-jndi> 8 <db-url>jdbc:oracle:thin:@172.21.129.51:1521:orcl</db-url> 9 <db-username>mu_fsu</db-username> 10 <db-password>mu_fsu</db-password> 11 ... 12 </properties> 13 <!-- 預設啟用本環境 --> 14 <activation> 15 <activeByDefault>true</activeByDefault> 16 </activation> 17 </profile> 18 <profile> 19 <!-- 生產環境 --> 20 <id>pro</id> 21 <properties> 22 ... 23 <db-source-jdbc>NONE</db-source-jdbc> 24 <db-source-jndi>dataSource</db-source-jndi> 25 ... 26 </properties> 27 </profile> 28 </profiles>
這樣,mvn clean package -P local打包本地開發環境時,將生成
1 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 2 destroy-method="close"> 3 <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> 4 <property name="url" value="jdbc:oracle:thin:@172.21.129.***:1521:orcl" /> 5 <property name="username" value="***" /> 6 <property name="password" value="***" /> 7 <property name="defaultAutoCommit" value="false" /> 8 <property name="initialSize" value="2" /> 9 <property name="maxActive" value="10" /> 10 <property name="maxWait" value="60000" /> 11 </bean> 12 13 <bean id="NONE" class="org.springframework.jndi.JndiObjectFactoryBean"> 14 <property name="jndiName" value="appDS" /> 15 </bean>
而打包生產環境 mvn clean package -P pro時,生成
1 <bean id="NONE" class="org.apache.commons.dbcp.BasicDataSource" 2 destroy-method="close"> 3 <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> 4 <property name="url" value="${db-url}" /> 5 <property name="username" value="${db-username}" /> 6 <property name="password" value="${db-password}" /> 7 <property name="defaultAutoCommit" value="false" /> 8 <property name="initialSize" value="2" /> 9 <property name="maxActive" value="10" /> 10 <property name="maxWait" value="60000" /> 11 </bean> 12 13 <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> 14 <property name="jndiName" value="appDS" /> 15 </bean>
spring配置的其它跟資料庫相關的bean,約定引用dataSource這個名稱的bean即可
2、不同webserver環境,依賴jar包,是否打包的問題
weblogic上,允許多個app,把共用的jar包按約定打包成一個war檔案,以library的方式部署,然後各應用在WEB-INF/weblogic.xml中,用類似下面的形式
1 <?xml version="1.0" encoding="utf-8"?> 2 <weblogic-web-app xmlns="http://www.bea.com/ns/weblogic/90"> 3 ... 4 <library-ref> 5 <library-name>my-share-lib</library-name> 6 </library-ref> 7 </weblogic-web-app>
指定共享library 的名稱即可。這樣的好處是,即節省了伺服器開銷,而且各app打包時,就不必再重複打包這些jar檔案,打包後的體積大大減少,上傳起來會快很多。
而其它webserver上卻未必有這個機制,一般為了方便,我們開發時,往往採用一些輕量級的webserver,比如:tomcat,jetty,jboss 之類,正式部署時才釋出到weblogic下,這樣帶來的問題就是,本機打包時,要求這些依賴jar包,全打包到app的WEB-INF/lib下;而生產環境下,各應用的WEB-INF/lib下並不需要這些jar檔案,同樣還是用profile來搞定,先處理pom.xml,把依賴項改成類似下面的形式:
1 <dependency> 2 <groupId>dom4j</groupId> 3 <artifactId>dom4j</artifactId> 4 <version>1.6.1</version> 5 <scope>${jar.scope}</scope> 6 </dependency>
即scope這裡,用一個佔位符來代替,然後profile這樣配置
1 <profile> 2 <!-- 本機環境 --> 3 <id>local</id> 4 <properties> 5 <jar.scope>compile</jar.scope> 6 ... 7 </properties> 8 <!-- 預設啟用本環境 --> 9 <activation> 10 <activeByDefault>true</activeByDefault> 11 </activation> 12 </profile> 13 <profile> 14 <!-- 生產環境 --> 15 <id>pro</id> 16 <properties> 17 <jar.scope>provided</jar.scope> 18 ... 19 </properties> 20 </profile>
在maven裡,如果一個依賴項的scope是provided,表示由容器提供,打包時將不會打包進最終的package裡,所以這樣配置後,生產環境打包時,依賴項的scope全變成了provided,即不打包進war檔案,而本機環境下,因為scope是compile,所以會打包到war裡