Maven的pom.xml介紹

簡介

  pom.xml文件是Maven進行工作的主要配置文件。在這個文件中我們可以配置Maven項目的groupId、artifactId和version等Maven項目必須的元素;可以配置Maven項目需要使用的遠程倉庫;可以定義Maven項目打包的形式;可以定義Maven項目的資源依賴關係等等。對於一個最簡單的pom.xml的定義必須包含modelVersion、groupId、artifactId和version這四個元素,當然這其中的元素也是可以從它的父項目中繼承的。在Maven中,使用groupId、artifactId和version組成groupdId:artifactId:version的形式來唯一確定一個項目。

pom.xml的繼承、聚合與依賴

  我們知道Maven在建立項目的時候是基於Maven項目下的pom.xml進行的,我們項目依賴的信息和一些基本信息都是在這個文件裏面定義的。那如果當我們有多個項目要進行,這多個項目有些配置內容是相同的,有些是要彼此關聯的,那如果按照傳統的做法的話我們就需要在多個項目中都定義這些重複的內容。這無疑是非常耗費時間和不易維護的。好在Maven給我們提供了一個pom的繼承和聚合的功能。
  對於使用java的人而言,繼承這個詞大家應該都不陌生。要繼承pom就需要有一個父pom,在Maven中定義了超級pom.xml,任何沒有申明自己父pom.xml的pom.xml都將默認繼承自這個超級pom.xml。
  先來看一下這個超級pom.xml的定義:

<project>  
  <modelVersion>4.0.0</modelVersion>  
  <name>Maven Default Project</name>  

  <repositories>  
    <repository>  
      <id>central</id>  
      <name>Maven Repository Switchboard</name>  
      <layout>default</layout>  
      <url>http://repo1.maven.org/maven2</url>  
      <snapshots>  
        <enabled>false</enabled>  
      </snapshots>  
    </repository>  
  </repositories>  

  <pluginRepositories>  
    <pluginRepository>  
      <id>central</id>  
      <name>Maven Plugin Repository</name>  
      <url>http://repo1.maven.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>  
    <!-- TODO: MNG-3731 maven-plugin-tools-api < 2.4.4 expect this to be relative... -->  
    <scriptSourceDirectory>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>  
       <plugins>  
         <plugin>  
           <artifactId>maven-antrun-plugin</artifactId>  
           <version>1.3</version>  
         </plugin>        
         <plugin>  
           <artifactId>maven-assembly-plugin</artifactId>  
           <version>2.2-beta-2</version>  
         </plugin>          
         <plugin>  
           <artifactId>maven-clean-plugin</artifactId>  
           <version>2.2</version>  
         </plugin>  
         <plugin>  
           <artifactId>maven-compiler-plugin</artifactId>  
           <version>2.0.2</version>  
         </plugin>  
         <plugin>  
           <artifactId>maven-dependency-plugin</artifactId>  
           <version>2.0</version>  
         </plugin>  
         <plugin>  
           <artifactId>maven-deploy-plugin</artifactId>  
           <version>2.4</version>  
         </plugin>  
         <plugin>  
           <artifactId>maven-ear-plugin</artifactId>  
           <version>2.3.1</version>  
         </plugin>  
         <plugin>  
           <artifactId>maven-ejb-plugin</artifactId>  
           <version>2.1</version>  
         </plugin>  
         <plugin>  
           <artifactId>maven-install-plugin</artifactId>  
           <version>2.2</version>  
         </plugin>  
         <plugin>  
           <artifactId>maven-jar-plugin</artifactId>  
           <version>2.2</version>  
         </plugin>  
         <plugin>  
           <artifactId>maven-javadoc-plugin</artifactId>  
           <version>2.5</version>  
         </plugin>  
         <plugin>  
           <artifactId>maven-plugin-plugin</artifactId>  
           <version>2.4.3</version>  
         </plugin>  
         <plugin>  
           <artifactId>maven-rar-plugin</artifactId>  
           <version>2.2</version>  
         </plugin>         
         <plugin>                 
           <artifactId>maven-release-plugin</artifactId>  
           <version>2.0-beta-8</version>  
         </plugin>  
         <plugin>                  
           <artifactId>maven-resources-plugin</artifactId>  
           <version>2.3</version>  
         </plugin>  
         <plugin>  
           <artifactId>maven-site-plugin</artifactId>  
           <version>2.0-beta-7</version>  
         </plugin>  
         <plugin>  
           <artifactId>maven-source-plugin</artifactId>  
           <version>2.0.4</version>  
         </plugin>          
         <plugin>  
            <artifactId>maven-surefire-plugin</artifactId>  
            <version>2.4.3</version>  
         </plugin>  
         <plugin>  
           <artifactId>maven-war-plugin</artifactId>  
           <version>2.1-alpha-2</version>  
         </plugin>  
       </plugins>  
     </pluginManagement>  
  </build>  

  <reporting>  
    <outputDirectory>${project.build.directory}/site</outputDirectory>  
  </reporting>  
  <profiles>  
    <profile>  
      <id>release-profile</id>  

      <activation>  
        <property>  
          <name>performRelease</name>  
          <value>true</value>  
        </property>  
      </activation>  

      <build>  
        <plugins>  
          <plugin>  
            <inherited>true</inherited>  
            <groupId>org.apache.maven.plugins</groupId>  
            <artifactId>maven-source-plugin</artifactId>  
            <executions>  
              <execution>  
                <id>attach-sources</id>  
                <goals>  
                  <goal>jar</goal>  
                </goals>  
              </execution>  
            </executions>  
          </plugin>  
          <plugin>  
            <inherited>true</inherited>  
            <groupId>org.apache.maven.plugins</groupId>  
            <artifactId>maven-javadoc-plugin</artifactId>  
            <executions>  
              <execution>  
                <id>attach-javadocs</id>  
                <goals>  
                  <goal>jar</goal>  
                </goals>  
              </execution>  
            </executions>  
          </plugin>  
          <plugin>  
            <inherited>true</inherited>  
            <groupId>org.apache.maven.plugins</groupId>  
            <artifactId>maven-deploy-plugin</artifactId>  
            <configuration>  
              <updateReleaseInfo>true</updateReleaseInfo>  
            </configuration>  
          </plugin>  
        </plugins>  
      </build>  
    </profile>  
  </profiles>  

</project>  

  對於一個pom.xml來說有幾個元素是必須定義的,一個是project根元素,然後就是它裏面的modelVersion、groupId、artifactId和version。由上面的超級pom.xml的內容我們可以看到pom.xml中沒有groupId、artifactId和version的定義,所以我們在建立自己的pom.xml的時候就需要定義這三個元素。和java裏面的繼承類似,子pom.xml會完全繼承父pom.xml中所有的元素,而且對於相同的元素,一般子pom.xml中的會覆蓋父pom.xml中的元素,但是有幾個特殊的元素它們會進行合併而不是覆蓋。這些特殊的元素是:

  • dependencies
  • developers
  • contributors
  • plugin列表,包括plugin下面的reports
  • resources

繼承

被繼承項目與繼承項目是父子目錄關係

現在假設我們有一個項目projectA,它的pom.xml定義如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>com.houmanager.mavenTest</groupId>  
  <artifactId>projectA</artifactId>  
  <packaging>jar</packaging>  
  <version>1.0-SNAPSHOT</version>  
</project>  

  然後我們有另一個項目projectB,而且projectB是跟projectA的pom.xml文件處於同一個目錄下,這時候如果projectB需要繼承自projectA的話我們可以這樣定義projectB的pom.xml文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  
  <parent>  
    <groupId>com.houmanager.mavenTest</groupId>  
    <artifactId>projectA</artifactId>  
    <version>1.0-SNAPSHOT</version>  
  </parent>  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>com.houmanager.mavenTest</groupId>  
  <artifactId>projectB</artifactId>  
  <packaging>jar</packaging>  
  <version>1.0-SNAPSHOT</version>  
</project>  

由projectB的pom.xml文件的定義我們可以知道,當需要繼承指定的一個Maven項目時,我們需要在自己的pom.xml中定義一個parent元素,在這個元素中指明需要繼承項目的groupId、artifactId和version。

被繼承項目與繼承項目的目錄結構不是父子關係

當被繼承項目與繼承項目的目錄結構不是父子關係的時候,我們再利用上面的配置是不能實現Maven項目的繼承關係的,這個時候我們就需要在子項目的pom.xml文件定義中的parent元素下再加上一個relativePath元素的定義,用以描述父項目的pom.xml文件相對於子項目的pom.xml文件的位置。
假設我們現在還是有上面兩個項目,projectA和projectB,projectB還是繼承自projectA,但是現在projectB不在projectA的子目錄中,而是與projectA處於同一目錄中。這個時候projectA和projectB的目錄結構如下:
——projectA
  ——pom.xml
——projectB
  ——pom.xml
這個時候我們可以看出projectA的pom.xml相對於projectB的pom.xml的位置是“../projectA/pom.xml”,所以這個時候projectB的pom.xml的定義應該如下所示:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  
  <parent>  
    <groupId>com.houmanager.mavenTest</groupId>  
    <artifactId>projectA</artifactId>  
    <version>1.0-SNAPSHOT</version>  
       <relativePath>../projectA/pom.xml</relativePath>  
  </parent>  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>com.houmanager.mavenTest</groupId>  
  <artifactId>projectB</artifactId>  
  <packaging>jar</packaging>  
  <version>1.0-SNAPSHOT</version>  
</project> 

聚合

  對於聚合這個概念搞java的人應該都不會陌生。先來說說我對聚合和被聚合的理解,比如說如果projectA聚合到projectB,那麼我們就可以說projectA是projectB的子模塊, projectB是被聚合項目,也可以類似於繼承那樣稱爲父項目。對於聚合而言,這個主體應該是被聚合的項目。所以,我們需要在被聚合的項目中定義它的子模塊,而不是像繼承那樣在子項目中定義父項目。具體做法是:
Ø 修改被聚合項目的pom.xml中的packaging元素的值爲pom
Ø 在被聚合項目的pom.xml中的modules元素下指定它的子模塊項目
對於聚合而言,當我們在被聚合的項目上使用Maven命令時,實際上這些命令都會在它的子模塊項目上使用。這就是Maven中聚合的一個非常重要的作用。假設這樣一種情況,你同時需要打包或者編譯projectA、projectB、projectC和projectD,按照正常的邏輯我們一個一個項目去使用mvn compile或mvn package進行編譯和打包,對於使用Maven而言,你還是這樣使用的話是非常麻煩的。因爲Maven給我們提供了聚合的功能。我們只需要再定義一個超級項目,然後在超級項目的pom.xml中定義這個幾個項目都是聚合到這個超級項目的。之後我們只需要對這個超級項目進行mvn compile,它就會把那些子模塊項目都進行編譯。

被聚合項目和子模塊項目在目錄結構上是父子關係

還拿上面定義的projectA和projectB來舉例子,現在假設我們需要把projectB聚合到projectA中。projectA和projectB的目錄結構如下所示:
——projectA
  ——projectB
    —–pom.xml
  ——pom.xml
這個時候projectA的pom.xml應該這樣定義:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>com.houmananger.mavenTest</groupId>  
  <artifactId>projectA</artifactId>  
  <version>1.0-SNAPSHOT</version>  
  <packaging>pom</packaging>  
  <modules>  
       <module>projectB</module>  
  </modules>  
</project>  

  由上面的定義我們可以看到被聚合的項目的packaging類型應該爲pom,而且一個項目可以有多個子模塊項目。對於聚合這種情況,我們使用子模塊項目的artifactId來作爲module的值,表示子模塊項目相對於被聚合項目的地址,在上面的示例中就表示子模塊projectB是處在被聚合項目的子目錄下,即與被聚合項目的pom.xml處於同一目錄。這裏使用的module值是子模塊projectB對應的目錄名projectB,而不是子模塊對應的artifactId。這個時候當我們對projectA進行mvn package命令時,實際上Maven也會對projectB進行打包。

被聚合項目與子模塊項目在目錄結構上不是父子關係

那麼當被聚合項目與子模塊項目在目錄結構上不是父子關係的時候,我們應該怎麼來進行聚合呢?還是像繼承那樣使用relativePath元素嗎?答案是非也,具體做法是在module元素中指定以相對路徑的方式指定子模塊。我們來看下面一個例子。
繼續使用上面的projectA和projectB,還是需要把projectB聚合到projectA,但是projectA和projectB的目錄結構不再是父子關係,而是如下所示的這種關係:
——projectA
  ——pom.xml
——projectB
  ——pom.xml
這個時候projectA的pom.xml文件就應該這樣定義:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  <modelVersion>4.0.0</modelVersion>  

  <groupId>com.houmanager.mavenTest</groupId>  
  <artifactId>projectA</artifactId>  
  <version>1.0-SNAPSHOT</version>  
  <packaging>pom</packaging>  
  <modules>  
       <module>../projectB</module>  
  </modules>  
</project>  

  注意看module的值是“../projectB”,我們知道“..”是代表當前目錄的上層目錄,所以它表示子模塊projectB是被聚合項目projectA的pom.xml文件所在目錄(即projectA)的上層目錄下面的子目錄,即與projectA處於同一目錄層次。注意,這裏的projectB對應的是projectB這個項目的目錄名稱,而不是它的artifactId。

聚合與繼承同時進行

假設有這樣一種情況,有兩個項目,projectA和projectB,現在我們需要projectB繼承projectA,同時需要把projectB聚合到projectA。然後projectA和projectB的目錄結構如下:
——projectA
  ——pom.xml
——projectB
  ——pom.xml
  那麼這個時候按照上面說的那樣,projectA的pom.xml中需要定義它的packaging爲pom,需要定義它的modules,所以projectA的pom.xml應該這樣定義:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>com.houmanager.mavenTest</groupId>  
  <artifactId>projectA</artifactId>  
  <version>1.0-SNAPSHOT</version>  
  <packaging>pom</packaging>  
  <modules>  
       <module>../projectB</module>  
  </modules>  
</project>  

  而projectB是繼承自projectA的,所以我們需要在projectB的pom.xml文件中新增一個parent元素,用以定義它繼承的項目信息。所以projectB的pom.xml文件的內容應該這樣定義:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  <modelVersion>4.0.0</modelVersion>  
  <parent>  
       <groupId>com.houmanager.mavenTest</groupId>  
       <artifactId>projectA</artifactId>  
       <version>1.0-SNAPSHOT</version>  
       <relativePath>../projectA/pom.xml</relativePath>  
  </parent>  
  <groupId>com.houmanager.mavenTest</groupId>  
  <artifactId>projectB</artifactId>  
  <version>1.0-SNAPSHOT</version>  
  <packaging>jar</packaging>  
</project>  

依賴Dependency

項目之間的依賴是通過pom.xml文件裏面的dependencies元素下面的dependency元素進行的。一個dependency元素定義一個依賴關係。在dependency元素中我們主要通過依賴項目的groupId、artifactId和version來定義所依賴的項目。
先來看一個簡單的項目依賴的示例吧,假設我現在有一個項目projectA,然後它裏面有對junit的依賴,那麼它的pom.xml就類似以下這個樣子:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>com.houmanager.mavenTest</groupId>  
  <artifactId>projectB</artifactId>  
  <version>1.0-SNAPSHOT</version>  
  <packaging>jar</packaging>  

  <dependencies>  
    <dependency>  
      <groupId>junit</groupId>  
      <artifactId>junit</artifactId>  
      <version>3.8.1</version>  
      <scope>test</scope>  
              <optional>true</optional>  
    </dependency>  
  </dependencies>  
</project>  

在dependency元素中除了可以指定依賴項目的groupId、artifactId和version之外,還可以指定以下元素:

  • type:對應於依賴項目的packaging類型,默認是jar
  • scope:表示依賴項目的一個作用範圍。scope的主要取值範圍如下(還有一個是在Maven2.0.9以後版本才支持的import,關於import作用域將在後文《Dependency介紹》中做介紹):

  • compile:這是它的默認值,這種類型很容易讓人產生誤解,以爲只有在編譯的時候纔是需要的,其實這種類型表示所有的情況都是有用的,包括編譯和運行時。而且這種類型的依賴性是可以傳遞的。

  • provided:這個跟compile很類似,但是它表示你期望這個依賴項目在運行時由JDK或者容器來提供。這種類型表示該依賴只有在測試和編譯的情況下才有效,在運行時將由JDK或者容器提供。這種類型的依賴性是不可傳遞的。
  • runtime:這種類型表示該依賴在編譯的時候不是必須的,只有在運行的時候纔是必須的。
  • test:這表示這種依賴只有測試的時候才需要,正常情況下是不需要的。
  • system:這種類型跟provided類似,唯一不同的就是這種類型的依賴我們要自己提供jar包,這需要與另一個元素systemPath來結合使用。systemPath將指向我們系統上的jar包的路徑,而且必須是給定的絕對路徑。
  • systemPath:上面已經說過了這個元素是在scope的值爲system的時候用於指定依賴的jar包在系統上的位置的,而且是絕對路徑。該元素必須在依賴的 jar包的scope爲system時才能使用,否則Maven將報錯。
  • optional:當該項目本身作爲其他項目的一個依賴時標記該依賴爲可選項。假設現在projectA有一個依賴性projectB,我們把projectB這個依賴項設爲optional,這表示projectB在projectA的運行時不一定會用到。這個時候如果我們有另一個項目projectC,它依賴於projectA,那麼這個時候因爲projectB對於projectA是可選的,所以Maven在建立projectC的時候就不會安裝projectB,這個時候如果projectC確實需要使用到projectB,那麼它就可以定義自己對projectB的依賴。當一個依賴是可選的時候,我們把optional元素的值設爲true,否則就不設置optional元素。
  • exclusions:考慮這樣一種情況,我們的projectA依賴於projectB,然後projectB又依賴於projectC,但是在projectA裏面我們不需要projectB依賴的projectC,那麼這個時候我們就可以在依賴projectB的時候使用exclusions元素下面的exclusion排除projectC。這個時候我們可以這樣定義projectA對projectB的依賴:
<dependencies>  
     <dependency>  
            <groupId>com.houmanager.mavenTest</groupId>  
            <artifactId>projectB</artifactId>  
            <version>1.0-SNAPSHOT</version>  
            <exclusions>  
                   <exclusion>  
                          <groupId>com.houmanager.mavenTest</groupId>  
                          <artifactId>projectC</artifactId>  
                   </exclusion>  
            </exclusions>  
     </dependency>  
</dependencies>  

屬性

在pom.xml文件中我們可以使用${propertyName}的形式引用屬性。這個propertyName有以下幾種形式:

  • env.propertyName:這種形式表示引用的是環境變量,比如我們需要引用當前系統的環境變量PATH的時候,就可以使用${env.PATH}。
  • project.propertyName:這種形式表示引用的是當前這個pom.xml中project根元素下面的子元素的值。比如我們需要引用當前project下面的version的時候,就可以使用${project.version}。
  • settings.propertyName:這種形式引用的是Maven本地配置文件settings.xml或本地Maven安裝目錄下的settings.xml文件根元素settings下的元素。比如我們需要引用settings下的本地倉庫localRepository元素的值時,我們可以用${settings.localRepository}
  • java的系統屬性,所有在java中使用java.lang.System.getProperties()能夠獲取到的屬性都可以在pom.xml中引用,比如${java.home}。
  • pom.xml中properties元素下面的子元素作爲屬性。假如在pom.xml中有如下一段代碼<properties><hello.world>helloWorld</hello.world></properties>,那麼我們就可以使用${hello.world}引用到對應的helloWorld。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章