一、什麼是POM?
POM是Project Object Model的縮寫,是Maven工作的基礎單元;POM.xml是一個包含關於Maven項目信息和配置詳情的XML文件,是用來構建(build)項目的;它包含大多數項目的默認值;例如,構建項目的【target】文件夾;例如,資源文件夾——【src/main/java】;例如測試資源文件夾——【src/test/java】等等;當執行一個任務或目標,Maven會在當前文件夾內找POM文件。然後讀取POM裏的信息,獲取需要的配置信息,然後執行目標;
一些POM裏的特殊配置是項目的依賴(Project Dependencies);這裏的依賴指的是項目依賴的jar包;還有一些事插件或可執行的目標,構建配置等;其他的信息例如項目版本,描述,開發者,郵件列表等都可以被特別定義;
二、超級POM
超級POM是Maven默認的POM,所有的POM文件們都繼承了這個超級POM,除非明確定義了不繼承;超級POM文件被你創建的其他POM文件們繼承,目前最新的超級POM文件是3.5.4;(你可以理解爲所有POM文件的基類,父類);下面是一個樣例
<project>
<modelVersion>4.0.0</modelVersion>
<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
</pluginRepository>
</pluginRepositories>
<build>
<directory>${project.basedir}/target</directory>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<finalName>${project.artifactId}-${project.version}</finalName>
<testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
</testResource>
</testResources>
<pluginManagement>
<!-- NOTE: These plugins will be removed from future versions of the super POM -->
<!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) -->
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
</plugin>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<reporting>
<outputDirectory>${project.build.directory}/site</outputDirectory>
</reporting>
<profiles>
<!-- NOTE: The release profile will be removed from future versions of the super POM -->
<profile>
<id>release-profile</id>
<activation>
<property>
<name>performRelease</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<inherited>true</inherited>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<inherited>true</inherited>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<inherited>true</inherited>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<updateReleaseInfo>true</updateReleaseInfo>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
三、最簡單的POM
最簡單的POM文件要求有一下5個部分:
- 項目根目錄;
- 模塊版本-必須被設置成4.0.0;
- 組別ID-項目的組別的ID;
- 產品ID-項目產品的ID;
- 版本-在特定組別下的項目產品的版本;
下面是一個例子
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</project>
一個POM文件會要求配置你的groupId,artifactId和版本號;這3個值可以完整的定義一個產品;以<groupId>:<artifactId>:<version>
的形式;按照上面的例子,上面項目完整的產品名是:
com.mycompany.app:my-app:1
同樣的,第一節提到的,如果沒有明確定義配置信息,Maven會使用默認值。其中一種默認值是打包類型(packaging type);每個Maven 項目都有一個打包類型;如果POM裏沒有明確定義,那麼,默認的打包類型會是jar包;
此外,你可以看到,最簡單的POM文件裏,倉庫(repositories)是沒有明確配置的。如果你使用最簡單的POM文件來構建項目,他會繼承超級POM的倉庫配置;因此,當Maven看到最簡單POM文件裏的依賴,他會直接去中央倉庫去下載(http://repo.maven.apache.org/maven2
),這是所有POM文件的超級POM配置倉庫;
四、項目繼承
POM文件裏元素的會被合併如下:
- 依賴jar包
- 開發者和貢獻者
- 插件列表(包括報告)
- 匹配到id的插件;
- 插件配置
- 資源
超級POM文件是一個項目繼承的經典例子,但是,如果你想通過特定的POM中父類元素引入你自己的父類POM文件,建議看看以下案例演示:
4.1、案例一
舉例如下,讓我們複用前面的產品,com.mycompany.app:my-app:1
,並且讓我們引入一個其他的產品:com.mycompany.app:my-module:1
;
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
讓我們特別定義文件目錄結構如下:
.
|-- my-module
| `-- pom.xml
`-- pom.xml
注意:my-module/pom.xml
是com.mycompany.app:my-module:1
產品的POM文件;
而pom.xml
是com.mycompany.app:my-app:1
產品的POM文件;
解決方案
現在,如果我們把com.mycompany.app:my-app:1
設爲com.mycompany.app:my-module:1
的父類項目;那麼,我們必須修改com.mycompany.app:my-module:1
的POM文件如下:(即,我們再子類的POM文件裏修改,添加父類的信息)
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
注意,我們添加了一個標籤組節,這個組節允許我們在POM文件裏特別定義產品的父類信息;我們通過定義其父類POM的【全限定產品名】(fully qualified artifact name);我們的模塊就可以繼承其父類POM了;
除此之外,如果我們想讓我們模塊的groupID或version和其父類一樣,我們可以移除子類模塊POM文件中的groupId或version;
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-module</artifactId>
</project>
4.2、案例二
然而,上述案例一的那種情況,必須是父項目已經在我們本地倉庫安裝(installed)或者被特別定義了結構pom.xml
父pom.xml是一個比你當前模塊的pom.xml高級的文件夾;
但是,如果父項目沒有被安裝或者文件夾結構是如下的例子:
.
|-- my-module
| `-- pom.xml
`-- parent
`-- pom.xml
解決方案:
添加文件夾結構地址(或任意其他目錄地址),我們可以添加關聯路徑<relativePath>
原來到父組節裏
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-module</artifactId>
</project>
作爲名字的建議,模塊的相對路徑的pom.xml是父pom.xml
五、項目聚合
項目的聚類類似於項目的繼承,但是不是在模塊的父pom文件,而是在父POM裏;通過這樣的操作,父項目可以知道他的子模塊,並且,如果Mavne命令是在父項目裏調用的,Maven命令可以在父模塊中執行;爲了做模塊聚合,你必須做如下操作:
1. 修改父POMs打包的值爲pom(而不是jar)
2. 特別定義父類的POM中子模塊的目錄
5.1、案例三
下面給定了一個原始的產品的POMs和目錄結構
com.mycompany.app:my-app:1's POM
的POM
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</project>
和
com.mycompany.app:my-module:1's POM
的POM文件
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
目錄結構
.
|-- my-module
| `-- pom.xml
`-- pom.xml
解決方案
如果我們想將my-module
模塊聚合到 my-app
模塊,我們需要緊緊修改my-app
模塊的POM:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<packaging>pom</packaging>
<modules>
<module>my-module</module>
</modules>
</project>
在修訂後的com.mycompany.app:my-app:1
模塊,打包的組節和模塊的組節被添加進去了;爲了打包,他的值被修改爲了“pom”,並且模塊的組節,我們有元素:<module>my-module</module>
模塊的值是com.mycompany.app:my-app:1
相對 com.mycompany.app:my-module:1's POM
的相對路徑;(我們特別用了模塊的產品的模塊目錄名);
現在,無論Maven命令處理 com.mycompany.app:my-app:1
,相同的maven命令會同時在 com.mycompany.app:my-module:1
裏執行;此外,一些命令(目標特別定義)的會被項目特殊處理;
5.2、案例四
但是,如果我們按照下面的來修改目錄呢?
.
|-- my-module
| `-- pom.xml
`-- parent
`-- pom.xml
父類的POM會不會被模塊特別定義?
解決方案:
答案?和案例3一樣,通過特別定義模塊的相對路徑:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<packaging>pom</packaging>
<modules>
<module>../my-module</module>
</modules>
</project>
即可;
- [ ]
六、項目繼承和項目聚合的比較
如果你有好幾個Maven工程,並且他們都有相似的配置,你可以通過添加父類項目和相似的配置文件來重構項目;所有你要做的就是讓你的Maven工程繼承其父類項目,並且配置必須與其一致;
並且,如果你有一個項目組,你要構建或者同時處理,你可以創建一個父工程,並且讓父工程來定義它的子類;這樣,你緊緊需要構建父項目,其他的子項目就會自動執行,不需要你操心了;
但是,同樣的,你如果既有項目繼承又有項目依賴;注意,你可以特定一個父項目,同時,定義這個父項目的子項目;你必須遵循下面3條規則:
1. 在父POM定義其所有的子項目POM;
2. 修改父項目的POMs的打包方式爲pom
3. 特別定義父POM的目錄給子項目;
6.1、案例5
給定了如下原始的POMs的產品
com.mycompany.app:my-app:1’s POM
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</project>
com.mycompany.app:my-module:1’s POM
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
目錄結構如下:
.
|-- my-module
| `-- pom.xml
`-- parent
`-- pom.xml
解決方案
爲了兩個項目都繼承和聚合,你僅僅需要遵從上述3條內容;
com.mycompany.app:my-app:1’s POM
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<packaging>pom</packaging>
<modules>
<module>../my-module</module>
</modules>
</project>
com.mycompany.app:my-module:1’s POM
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-module</artifactId>
</project>
注意:配置文件的繼承相同的繼承策略;
七、項目插值與變量
Maven鼓勵的一個經驗就是【不要重複】;然而,如果你需要使用在不同的地方多次使用相同的變量;爲了幫助變量是唯一定義的,Maven允許你在POM文件裏預定義自己的變量;
例如,爲了得到 project.version
變量,你可以定義如下:
<version>${project.version}</version>
注意一個事實,變量在被繼承之後處理;這意味着,如果一份父項目要使用一個變量,如果這個變量定義在子項目中,而不是父項目中,則子項目中的變量將會被最終使用;