使用Maven那么久了,你對企業級Maven的核心配置了解多少?


寫在前面

相信從事Java工作的小伙伴們多多少少都會接觸到Maven。使用Maven來搭建項目,能夠極大的方便我們構建項目的依賴關系,對於項目中需要依賴的Jar包,也只是簡單的在pom.xml中進行配置即可。可以說,Maven能夠極大的提高我們的開發效率和項目的維護效率,能夠統一項目的依賴環境,提高團隊的協作效率。然而,盡管使用Maven的小伙伴很多,但真正掌握了Maven核心配置的又有多少呢?

項目依賴

項目依賴是指Maven 通過依賴傳播、依賴優先原則、可選依賴、排除依賴、依賴范圍等特性來管理項目classpath。

依賴傳播特性

我們的項目通常需要依賴第三方組件,而第三方組件又會依賴其它組件遇到這種情況Maven會將依賴網絡中的所有節點都會加入classpath當中,這就是Maven的依賴傳播特性。

例如下面的配置

<!-- 添加spring mvc依賴-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.2.9.RELEASE</version>
</dependency>

項目直接依賴了spring-webmvc 叫直接依賴,而對commons-logging 依賴是通過webmvc傳遞的所以叫間接依賴。

依賴優先原則

基於依賴傳播特性,導致整個依賴網絡會很復雜,難免會出現相同組件不同版本的情況。Maven此時會基於依賴優先原則選擇其中一個版本。

  • 第一原則:最短路徑優先。
  • 第二原則:相同路徑下配置在前的優先。

第一原則示例

<!-- 直接添加commons-logging -->
<dependency>
  <groupId>commons-logging</groupId>
  <artifactId>commons-logging</artifactId>
  <version>1.2</version>
</dependency>

上述例子中commons-logging 通過spring-webmvc 依賴了1.1.3,而項目中直接依賴了1.2,基於最短路徑原則項目最終引入的是1.2 版本。

第二原則示例

主要步驟如下所示:

(1)添加一個新工程Project B

(2) 配置Project B 依賴 spring-web.3.2.9-RELEASE

(3)當前工程直接依賴 Project B

配置完之后,當前工程 project A 有兩條路徑可以依賴 spring-web,選擇哪一條 就取決於 對 webmvc 和 Project B的配置先后順序。

  • Project A==> spring-webmvc 5.2.9-RELEASE ==> spring-web 5.2.9-RELEASE
  • Project A==> Project B 1.0.SNAPSHOT ==>spring-web.3.2.9-RELEASE

注意:在同一pom文件,第二原則不在適應。如下配置,最終引用的是1.2 版本,而不是配置在前面的1.1.1版本。

<!-- 在1.2 之前添加 commons-logging -->
<dependency>
 <groupId>commons-logging</groupId>
 <artifactId>commons-logging</artifactId>
 <version>1.1.1</version>
</dependency>

<dependency>
 <groupId>commons-logging</groupId>
 <artifactId>commons-logging</artifactId>
 <version>1.2</version>
</dependency>

可選依賴

可選依賴表示這個依賴不是必須的。通過在<dependency></dependency>中添 加<optional>true</optional> 表示,默認是不可選的。可選依賴不會被傳遞。

排除依賴

即排除指定的間接依賴。通過配置<exclusions></exclusions>配置排除指定組件。

例如,我們可以使用下面的配置來排除對於spring-web的依賴。

<!-- 排除指定項目 -->
<exclusions>
  <exclusion>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
  </exclusion>
</exclusions>

依賴范圍

像junit 這個組件 我們只有在運行測試用例的時候去要用到,這就沒有必要在打包的時候把junit.jar 包過構建進去,可以通過Maven 的依賴范圍配置<scope></scope>來達到這種目的。Maven 總共支持以下四種依賴范圍:

  • compile(默認): 編譯范圍,編譯和打包都會依賴。
  • provided: 提供范圍,編譯時依賴,但不會打包進去。如:servlet-api.jar
  • runtime: 運行時范圍,打包時依賴,編譯不會。如:mysql-connector-java.jar
  • test: 測試范圍,編譯運行測試用例依賴,不會打包進去。如:junit.jar
  • system: 表示由系統中classpath指定。編譯時依賴,不會打包進去。配合<systemPath></systemPath> 一起使用。示例:java.home下的tool.jar

system 除了可以用於引入系統classpath 中包,也可以用於引入系統非maven 收錄的第三方Jar,做法是將第三方Jar放置在 項目的 lib 目錄下,然后配置 相對路徑,但因system 不會打包進去所以需要配合 maven-dependency-plugin 插件配合使用。當然,我還是推薦小伙伴們通過 將第三方Jar手動install 到倉庫。

接下來,我們就列舉幾個簡單的使用示例。

  • system 的通常使用方式
<dependency>
     <groupId>com.sun</groupId>
     <artifactId>tools</artifactId>
     <version>${java.version}</version>
     <scope>system</scope>
     <optional>true</optional>
     <systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
  • system 另外使用方式 ,將工程內的jar直接引入
<dependency>
  <groupId>jsr</groupId>
  <artifactId>jsr</artifactId>
  <version>3.5</version>
  <scope>system</scope>
  <optional>true</optional>
  <systemPath>${basedir}/lib/jsr305.jar</systemPath>
</dependency>
  • 通過插件 將system 的jar 打包進去
<plugin>
  <groupId>org.apache.maven.plugins</groupId>\
  <artifactId>maven-dependency-plugin</artifactId>
  <version>2.10</version>
  <executions>
    <execution>
      <id>copy-dependencies</id>
      <phase>compile</phase>
      <goals>
        <goal>copy-dependencies</goal>
      </goals>
      <configuration>
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/lib</outputDirectory>
        <includeScope>system</includeScope>
        <excludeGroupIds>com.sun</excludeGroupIds>
      </configuration>
    </execution>
  </executions>
</plugin>
  • 手動加入本地倉庫
mvn install:install-file -Dfile=mykit-transaction-message.jar -DgroupId=io.mykit -DartifactId=mykit-transaction-message -Dversion=1.0.0-RELEASE -Dpackaging=jar

項目聚合與繼承

聚合

聚合是指將多個模塊整合在一起,統一構建,避免一個一個的構建。聚合需要個父工程,然后使用 <modules></modules> 進行配置其中對應的是子工程的相對路徑。例如下面的配置。

<modules>
  <module>mykit-dao</module>
  <module>mykit-service</module>
</modules>

繼承

繼承是指子工程直接繼承父工程 當中的屬性、依賴、插件等配置,避免重復配置。繼承包括如下幾種方式。

  • 屬性繼承
  • 依賴繼承
  • 插件繼承

注意:上面的三個配置子工程都可以進行重寫,重寫之后以子工程的為准。

依賴管理

通過繼承的特性,子工程是可以間接依賴父工程的依賴,但多個子工程依賴有時並不一至,這時就可以在父工程中加入<dependencyManagement></dependencyManagement> 聲明該工程需要的JAR包,然后在子工程中引入。例如下面的配置。

<!-- 父工程中聲明 junit 4.12 -->
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
    </dependency>
  </dependencies>
</dependencyManagement>
<!-- 子工程中引入 -->
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
</dependency>

項目屬性

通過 <properties></properties> 配置屬性參數,可以簡化配置。例如下面的配置。

<!-- 配置proName屬性 -->
<properties>
  <projectName>projectName</projectName>
</properties>

我們可以在pom.xml文件中使用下面的形式來引入配置的參數。

${projectName}

接下來,我們再來看幾個Maven的默認屬性,如下所示。

  • ${basedir} 項目根目錄
  • ${version}表示項目版本;
  • ${project.basedir}同${basedir};
  • ${project.version}表示項目版本,與${version}相同;
  • ${project.build.directory} 構建目錄,缺省為target
  • ${project.build.sourceEncoding}表示主源碼的編碼格式;
  • ${project.build.sourceDirectory}表示主源碼路徑;
  • ${project.build.finalName}表示輸出文件名稱;
  • ${project.build.outputDirectory} 構建過程輸出目錄,缺省為target/classes

項目構建配置

構建資源配置

基本配置示例:

<defaultGoal>package</defaultGoal>
<directory>${basedir}/target2</directory>
<finalName>${artifactId}-${version}</finalName>

說明:

  • defaultGoal:執行構建時默認的goal或phase,如jar:jar或者package等
  • directory:構建的結果所在的路徑,默認為${basedir}/target目錄
  • finalName:構建的最終結果的名字,該名字可能在其他plugin中被改變

resources 配置示例

<resources>
  <resource>
   <directory>src/main/java</directory>
   <includes>
     <include>**/*.MF</include>
     <include>**/*.xml</include>
   </includes>
   <filtering>true</filtering>
  </resource>
  <resource>
   <directory>src/main/resources</directory>
   <includes>
     <include>**/*</include>
     <include>*</include>
   </includes>
   <filtering>true</filtering>
  </resource>
 </resources>

說明:

  • resources:build過程中涉及的資源文件
  • targetPath:資源文件的目標路徑
  • directory:資源文件的路徑,默認位於${basedir}/src/main/resources/目錄下
  • includes:一組文件名的匹配模式,被匹配的資源文件將被構建過程處理
  • excludes:一組文件名的匹配模式,被匹配的資源文件將被構建過程忽略。同時被includes和excludes匹配的資源文件,將被忽略。
  • filtering:默認false ,true 表示 通過參數 對 資源文件中 的${key} 在編譯時進行動態變更。替換源 -Dkey 和pom 中的 值 或 中指定的properties 文件。

重磅福利

微信搜一搜【冰河技術】微信公眾號,關注這個有深度的程序員,每天閱讀超硬核技術干貨,公眾號內回復【PDF】有我准備的一線大廠面試資料和我原創的超硬核PDF技術文檔,以及我為大家精心准備的多套簡歷模板(不斷更新中),希望大家都能找到心儀的工作,學習是一條時而郁郁寡歡,時而開懷大笑的路,加油。如果你通過努力成功進入到了心儀的公司,一定不要懈怠放松,職場成長和新技術學習一樣,不進則退。如果有幸我們江湖再見!

另外,我開源的各個PDF,后續我都會持續更新和維護,感謝大家長期以來對冰河的支持!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM