Maven用戶都應該知道的一些事:關於依賴的常見問題

依賴範圍(scope)不同選項的區別

依賴範圍參數的作用是控制依賴在不同階段與classpath的關係,具體區別如下圖所示。

表中沒有列出的值是import,這個選項是用於引入dependencyManagement,下文會有介紹。

依賴調解,調解同一依賴的不同版本

假設你的項目有如下的依賴樹

POM
|-- A
|   `-- B 1.0
|-- C
|   `-- D
|       `-- B 2.0
`-- E
    `-- B 3.0

POM同時依賴了B的1.0和2.0版本,可Maven是不會重複引入相同座標的依賴的,那麼究竟哪個版本會生效呢?

Maven對於依賴的調解遵循兩個基本原則:

  • 1 依賴路徑長度短者優先;
  • 2 如果依賴路徑長度相同,則後聲明優先。

所以根據1,2.0版本被排除,根據2,3.0版本被實際引入。

如果你自己明確知道該引入哪個版本的B,那麼直接在POM中聲明B依賴就好了,因爲這時的依賴路徑是最短了。

可選依賴(optional)含義

可選依賴的作用就是聲明該依賴不被傳遞依賴。

POM
`-- A
   `-- B(optional)

這裏B不會被引入。

Super POM(Project Object Model)

Super POM是Maven自帶的全局POM文件,所有的POM文件都默認繼承了Super POM。其中定義了各種默認配置,以簡化POM文件的編寫。下面是Maven 3.5.4的Super 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>
    ...

Super POM中定義了中央依賴倉庫、中央插件倉庫,以及各種文件夾的默認路徑。

POM繼承

如果你的項目有多個模塊,通常每個模塊之間會有一些相同的公共的依賴,你可以把依賴聲明在模塊各自的POM中,如下所示。

.
|-- mod A
|   `-- pom.xml
|       `-- P(1.0)
`-- mod B
    `-- pom.xml
        `-- P(1.0)

這樣A模塊和B模塊都依賴了P,但是如果有天你想要修改P的版本,又希望A,B模塊依賴的P版本相同,那就得同時修改POM-A和POM-B,太不優雅了。

所以Maven提供了POM繼承功能,讓我們可以吧公共的依賴抽取出來。

.
|-- pom.xml (父POM)
|   `-- P(1.0)
|-- mod A
|   `-- pom.xml
`-- mod B
    `-- pom.xml

做法如上,在父POM中聲明依賴P,在AB模塊的POM中聲明對父POM的繼承,便能實現AB模塊對P依賴的引入。

AB模塊中加入下面一段,便能實現對父POM的繼承。

  <parent>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <version>1</version>
    <relativePath>../pom.xml</relativePath>
  </parent>

relativePath的默認值即是‘../pom.xml’,可以省略。

值得一提的是,這裏父POM並不需要知道子POM的信息。

總之,有了繼承,子模塊就能擁有父模塊同樣的依賴。

POM聚合

假設你的項目有多個模塊,通常每個模塊需要各自單獨構建,如果想要所有模塊能同時構建,則需要使用Maven的聚合功能。

使用聚合同樣需要建一個父POM

.
|-- pom.xml (父POM)
|-- A
|   `-- pom.xml
`-- B
    `-- pom.xml

父POM內容如下:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1</version>
  <packaging>pom</packaging>
 
  <modules>
    <module>A</module>
    <module>B</module>
  </modules>
</project>

其中packaging必須是pom,modules中聲明需要聚合的子模塊。
與繼承相反,子POM中不需要父POM的信息。

總之,有了聚合,所有對父模塊執行的Maven命令,同樣會對子模塊執行。

依賴管理(dependencyManagement)是什麼

在前面講繼承的時候,我們通過父POM使得AB兩個模塊都擁有了依賴P,但是如果我們現在添加一個模塊C,模塊C並不需要依賴P,只需要父POM中的其他配置和依賴,該怎麼辦呢?

這就要用到dependencyManagement這個配置了,dependencyManagement與dependencies元素不同在於並不會真的引入依賴,只是指定依賴的版本。

做法是在父POM中添加dependencyManagement配置

 <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>groupabc</groupId>
        <artifactId>p</artifactId>
        <version>1.0</version>
      </dependency>
  </dependencyManagement>

然後在AB模塊的POM中添加如下,注意不含版本信息。

  <dependencies>
    <dependency>
      <groupId>groupabc</groupId>
      <artifactId>p</artifactId>
    </dependency>
  </dependencies>  

如此一來,AB模塊都引入了依賴p的v1.0,而模塊C沒有引入依賴p。

另外還有pluginManagement與此類似,不過是針對插件而已。

參考文獻

Introduction to the POM

Introduction to the Dependency Mechanism

《Maven實戰》

轉載請保留原文地址:Maven用戶都應該知道的一些事:關於依賴的常見問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章