1. 程式人生 > >maven 映象倉庫與資原始檔

maven 映象倉庫與資原始檔

倉庫映象mirrors

      如果倉庫X可以提供倉庫Y儲存的所有內容,那麼就可以認為X是Y的一個映象。換句話說,任何一個可以從倉庫Y獲取的構建,都在夠從它的映象中獲取。舉個例子,http://maven.net.cn/content/groups/public/是中央倉庫http://repo1.maven.org/maven2/在中國的映象,由於地理位置,該映象往往能夠提供比中央倉庫更快的服務,因此,可以配置Maven使用該映象來代替中央倉庫。編輯settings.xml檔案。

<settings>

……

<mirrors>

<mirror>

<id>maven.net.cn</id>

<name>oneof the central mirrors in china</name>

<mirrorOf>central</mirrorOf>

</mirror>

</mirrors>

….

</settings>

該配置中,<mirrorOf>的值為central,表示該配置為中央倉庫的映象,任何對於中央倉庫的請求都會轉至該映象,使用者也可以使用同樣的方法配置其它倉庫的映象。另外三個元素id、name、url與一般倉庫配置無異,表示該倉庫的唯一識別符號、名稱以及地址。類似地,如果該映象需要認證,那基於該id配置倉庫認證,如下配置:

<settings>

….

<server>

      <id>maven.net.cn</id>

      <username>admin</username>

      <password>******</password>

    </server>

….

</settings>

關於映象的一個更加常用的做法是結合私服。由於私服可以代理任何外部公共倉庫(包括中央倉庫),因此,對於組織內部的maven使用者來說,使用一個私服地址就等於使用了所有需要的外部倉庫,這可以將配置集中到私服,從而簡化了maven本身的配置。在這種情況下,任何需要的構建都可以從私服獲得,私服就是所有倉庫的映象倉庫。我們可以配置這樣的一個映象,如下配置:

      <settings>

……

<mirrors>

<mirror>

<id>internal-repository</id>

<name>internalrepository manager</name>

<mirrorOf>*</mirrorOf>

</mirror>

</mirrors>

….

</settings>

該例中<mirrorOf>的值為星號,標識該配置是所有的maven倉庫的映象,任何對於遠端倉庫的請求都會轉至http://192.168.1.112:8081/nexus/content/groups/public。如果該映象倉庫需要認證,則配置id為internal-repository的<server>即可。

Maven還支援更高階的映象配置:

<mirrorOf>*</mirrorOf>:匹配所有遠端倉庫

<mirrorOf>external:*</mirrorOf>:除了localhost與file://協議的地址,匹配所有的遠端倉庫,也就是說,匹配所有不在本機上的遠端倉庫

<mirrorOf>repo1,repo2</mirrorOf>:匹配倉庫repo1和repo2,使用逗號分隔多個遠端倉庫

<mirrorOf>*,!repo1</mirrorOf>:除了repo1外,匹配所有遠端倉庫,使用感嘆號將倉庫從匹配中移除。

需要注意的是,由於映象倉庫完全遮蔽了被映象倉庫,當映象倉庫不穩定或者停止服務的時候,maven仍將無法訪問被映象倉庫,因而將無法下載構建。

配置properties屬性

通過在pom.xml配置<properties>元素,使用者可以自定義一個或者多個maven屬性,然後再pom的其它地方使用${屬性名稱}的方式引用該屬性,這個做法的最大意義在於消除重複。如,本來需要在多個地方重複宣告同樣的SpringFramework版本,現在只在一個地方宣告就可以,重複越多,好處就越明顯。因為這樣不僅減少了日後升級版本的工作量,也能降低錯誤發生的概率。我們來看下配置:

<project>

….

  <properties>

<springframework.version>4.1.1.RELEASE</springframework.version>

</properties>

  <dependencies>

 <dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-core</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-beans</artifactId>

<version>${springframework.version}</version>

</dependency>

    </dependencies>

….

</project>

內建屬性:主要有兩個常用內建屬性:

${basedir}標識專案的根目錄,即包含pom.xml檔案的目錄;${version}表示專案版本

pom屬性:使用者可以使用該類屬性引用pom檔案中對應元素的值。例如:${project.artifactId}就對應了<project><artifactId>元素的值,常用的pom屬性包括:

${project.build.sourceDirectory}:專案的主原始碼目錄,預設為src/main/java/

${project.build.testSourceDirectory}:專案的測試程式碼源目錄,預設為src/test/java/

${project.build.directory}:專案構建輸出目錄,預設為target/

${project.outputDirectory}:專案主程式碼編譯輸出目錄,預設為target/classes/

${project.testOutputDirectory}:專案測試程式碼編譯輸出目錄,預設是target/test-classes/

${project.groupId}:專案的groupId

${project.artifactId}:專案的artifactId

${project.version}:專案的version,與${version}等價

${project.build.finalName}:專案打包輸出檔案的名稱,預設為:${project.artifactId}-${project.version}。

這些屬性都對應一個pom元素,他們中一些屬性的預設值都是在超級pom中定義的,

1)自定義屬性:使用者可以在POM的<properties>元素下自定義Maven屬性,例如:

<project>

<properties>

<my.prop>hello</my.prop>

</properties>

….

</project>

然後再pom中其它地方使用${my.prop}的時候會被替換成hello。

2)Settings屬性:與POM屬性同理,使用者使用以settings.開頭的屬性引用settings.xml檔案中xml元素的值,如常用的${settings.localRepository}指向使用者本地倉庫的地址

3)java系統屬性:所有java系統屬性都可以使用maven屬性引用,例如${user.home}指向了使用者目錄。使用者可以使用mvn help:system檢視所有的java系統屬性

4)環境變數屬性:所有環境變數都可以使用env.開頭的maven屬性引用。例如${env.JAVA_HOME}指向了JAVA_HOME環境變數的值。使用者可以使用mvn help:system檢視所有環境變數

在一個多模組專案中,模組之間的依賴比較常見,這些模組通常會使用桐鄉的groupId和version。因此這個時候就可以使用POM屬性,如配置:

<dependencies>

<dependency>

       <groupId>${project.groupId}</groupId>

       <artifactId>module-task_one</artifactId>

       <version>${project.version}</version>

    </dependency>

<dependency>

       <groupId>${project.groupId}</groupId>

        <artifactId>module-task-two</artifactId>

       <version>${project.version}</version>

    </dependency>

</dependencies>

在配置中,當前模組依賴於module-task-one和module-task-two,這三個模組使用同樣的groupId和version,因此可以在依賴配置中使用POM屬性${project.groupId}和${project.version},表示這兩個依賴的groupId和version與當前模組一致。這樣,當專案版本升級的時候,就可以不再需要更改依賴的版本了。

大量的maven外掛用到了maven屬性,這意味著在配置外掛的時候同樣可以使用maven屬性來方便的自定義外掛行為。如:maven-surefire-plugin執行後預設的測試報告目錄為target/surefire-reports,這個實際上就是${project.build.directory}/surefire-reports,如果查閱該外掛的文件,會發現該外掛提供了reportsDirectory引數來配置測試報告目錄。因此如果想要修改測試報告目錄,例如改成target/test-reports,就可以按照如下配置:

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-surefire-plugin</artifactId>

<version>2.5</version>

<configuration>

<reportsDirectory>${project.build.directory}/test-reports</reportsDirectory>

</configuration>

</plugin>

資源過濾profile

為了應對環境的變化,首先需要使用maven屬性將這些將會發生變化的部分提取出來。如在連線資料庫使用的驅動類、URL、使用者名稱和密碼都可以發生變化,因此用maven屬性取代它們:

Database.jdbc.DriverClass= ${db.driver}

Database.jdbc.connectionURL= ${db.url}

Database.jdbc.username= ${db.username}

Database.jdbc.password= ${db.password}

這裡定義了四個maven屬性:db.driver、db.url、db.username、db.password,它們的命名是任何的,可以根據自己的實際情況定義合適的屬性名稱。

既然使用了maven屬性,就應該在某個地方定義它們。前面我們介紹過使用maven屬性,這裡介紹另外一種方式,使用一個額外的profile將其包裹,如下:

<profiles>

<profile>

<id>dev</id>

<properties>

<db.driver>con.mysql.jdbc.Driver</db.driver>

<db.url>jdbc:mysql://192.168.1.111:3306/test</db.url>

<db.username>dev</db.username>

<db.password>pass</db.password>

</ properties>

</profile>

</profiles>

上面定義的配置跟pom.xml下直接定義properties元素並無二致,這裡只是使用了一個id為dev的profile屬性,其目的是將開發環境下的配置與其它環境區別開來。我們來詳細解釋下profile。

有了屬性定義,配置檔案中也使用了這些屬性,一切OK了嗎?還不行。需要留意的是,maven屬性預設只有在pom中才會被解析。也就是說,${db.username}放到pom中會變成test,但是如果放到src/man/resources/目錄下的檔案中,構建的時候它仍然還是${db.username}。因此,需要讓maven解析資原始檔中的maven屬性。

資原始檔的處理其實就是maven-resources-plugin做的事情,它預設的行為只是將專案主資原始檔複製到主程式碼編譯輸出目錄,將測試資原始檔複製到測試程式碼的編譯輸出目錄中。不過只要通過一些配置,該外掛就能夠解析資原始檔中的maven屬性,即開始資源過濾。

Maven預設的主資源目錄和測試目錄定義是在超級pom中,要為資源目錄開啟過濾,只要在此基礎上新增一行filtering配置即可,如下配置:

<project>

......

<build>

<resources>

<resource>

<directory>${project.basedir}/src/main/resources</directory>

<filtering>true</filtering>

</resource>

</resources>

</build>

....

</project>

類似地,配置測試資源目錄過濾

<testResources>

<testResource>

<directory>${project.basedir}/src/test/resources</directory>

<filtering>true</filtering>

</testResource>

</testResources>

我們還可以為每個資源目錄提供不同的過濾配置,如下配置

<resources>

<resource>

<directory>${project.basedir}/src/main/resources</directory>

<filtering>true</filtering>

</resource>

<resource>

<directory>${project.basedir}/src/main/sql</directory>

<filtering>false</filtering>

</resource>

</resources>

如上配置了兩個資源目錄,其中src/main/resources開啟了過濾,而src/main/sql沒有啟動過濾。

到目前為止一切基本就緒了,我們將資料庫配置的變化部分提取成了maven屬性,在pom的profile中定義了這些屬性的值,並且為資源目錄開啟屬性過濾。最後,只需要在命令列啟用profile,maven就能夠在構建專案的時候使用profile中屬性值替換資料庫配置檔案中的屬性引用。

$mvn cleaninstall –Pdev

Mvn的-P引數標識在命令列啟用一個profile。這裡激活了id為dev的profile。構建完成後,輸出目錄中的資料庫配置就是一個開發環境的配置了:

Database.jdbc.DriverClass= com.mysql.jdbc.Driver

Database.jdbc.connectionURL= jdbc:mysql://localhost:3306/test

Database.jdbc.username= dev

Database.jdbc.password= pass

從上面內容我們看到,不同環境的構建很可能死不同的,典型的情況就是資料庫配置。初次之外,有些環境可能需要配置外掛使用恩地檔案,或者使用特殊版本的依賴,或者需要一個特殊的構建名稱。要想使得一個構建不做任何修改就能在任何環境下執行,往往是不可能的。為了能讓構建在各個環境下方便的移植,maven引入了profile的概念。Profile能夠在構建的時候修改pom的一個子集,或者新增額外的配置元素。使用者可以使用很多方式啟用profile,以實現構建在不同的環境下的移植。

針對不同環境的profile

上面我們引入一個針對開發環境的profile,類似地加入測試環境和產品環境的profile,如:

<profiles>

<profile>

<id>dev</id>

<properties>

<db.driver>con.mysql.jdbc.Driver</db.driver>

<db.url>jdbc:mysql://192.168.1.111:3306/test</db.url>

<db.username>dev</db.username>

<db.password>pass</db.password>

</ properties>

</profile>

<profile>

<id>test</id>

<properties>

<db.driver>con.mysql.jdbc.Driver</db.driver>

<db.url>jdbc:mysql://192.168.1.112:3306/test</db.url>

<db.username>test</db.username>

<db.password>pass</db.password>

</ properties>

</profile>

</profiles>

同樣的屬性在兩個profile中的值是不一樣的,dev profile提供了開發環境資料庫的配置,而test profile提供了測試環境資料庫的配置。類似的,我們還可以新增一個基於產品的資料庫配置。

現在,開發人員可以在使用mvn命令的時候再後面加上-Pdev啟用dev profile,而測試人員使用-Ptest啟用test profile

啟用profile

1)命令列啟用:使用者可以使用mvn命令列引數-P加上profile的id來啟用profile,多個id之間以逗號分隔。如:下面的命令激活了dev-x和dev-y兩個profile:

$mvn clean install –Pdev –x,dev –y

2) settings檔案顯示啟用:如果希望某個profile預設就一直處於啟用狀態,我們可以配置settings.xml檔案的active-Profiles元素,標識其配置在profile對於所有專案都處於啟用狀態,如下配置:

<settings>

….

<activeProfiles>

   <activeProfile>dev</activeProfile>

 </activeProfiles>

</settings>

3)系統屬性啟用:我們還可以配置當某個系統屬性存在的時候,自動啟用profile,如下配置:

<profiles>

<profile>

<activation>

<property>

<name>test</name>

</property>

</activation>

</profile>

</profiles>

還可以進一步配置當某系統屬性test存在,且值等於x的時候啟用profile,如:

<profiles>

<profile>

<activation>

<property>

<name>test</name>

<value>x</value>

</property>

</activation>

</profile>

</profiles>

不要忘了,使用者可以在命令列生命系統屬性。如:

$mvn cleaninstall –Dtest = x

因此,這其實也是一種從命令列啟用profile的方法,而且多個profile完全可以使用同一個系統屬性來啟用

4)作業系統環境啟用:profile還可以自動根據作業系統環境啟用,如果構建在不同的作業系統有差異,我們完全可以將這些差異寫進profile,然後配置他們自動基於作業系統環境啟用,如:

 <profiles>

<profile>

<activation>

<os>

<name>Windows 7</name>

<family>Windows</family>

<arch>x86</arch>

<version>5.1.2600</version>

</os>

</activation>

</profile>

</profiles>

這裡family的值包括Windows/UNIX/Mac等,而其他幾項name、arch、version,我們可以檢視環境中的系統屬性os.name、os.arch、os.version獲取

5)檔案存在與否獲取:maven能夠根據專案中某個檔案存在與否決定是否啟用,如:

 <profiles>

<profile>

<activation>

<file>

<missing>x.properties</missing>

<exists>y.properties</exists>

</file>

</activation>

</profile>

</profiles>

6)預設啟用:我們可以定義profile的時候制定其預設啟用,如:

 <profiles>

<profile>

<activation>

<activeByDefault>true</activeByDefault>

</activation>

</profile>

</profiles>

使用activeByDefault元素使用者可以指定profile自動啟用。不過需要注意的是,如果pom中有任何一個profile通過以後其它任何一種方式被激活了,所有的預設啟用配置都會失效。

如果專案中有很多profile,他們的啟用方法各異,我們怎麼知道哪些profile被激活了呢?maven-help-plugin提供了一個目標版主使用者瞭解當前啟用的profile:

$mvnhelp:active-profiles

Maven-help-plugin還有另外一個目標用來列出當前所有的profile:

$mvnhelp:all-profiles

Profile種類:

根據具體的需要,可以在一下位置宣告profile:

1)pom.xml:很顯然,pom.xml中宣告的profile只對當前專案有效

2)settings.xml:使用者目錄下.m2/settings.xml中的profile對本機上該使用者所有的maven專案有效

3)全域性setting.xml:maven安裝目錄下conf/settings.xml中的profile對本機上所有的maven專案有效

4)profiles.xml(maven2):還可以在專案根目錄下使用一個額外的profiles.xml檔案來宣告profile,不過該特性在maven3移除,建議將這類profile移植到settings.xml中。