版本管理

maven-dependency-plugin是一個常用的pluing,通常用來檢查專案裡倒底有哪些相依的jars.

mvn dependency:tree

會以樹狀圖的方式顯示整個相依jars的關係。

假設pom.xml類似如下:

<project ...>
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>6.1.3</version>
    </dependency>
    <dependency>
      <groupId>org.jdbi</groupId>
      <artifactId>jdbi3-spring5</artifactId>
      <version>3.43.0</version>
    </dependency>
  <dependencies>
</project>

mvn dependency:tree 大概顯示如下的Tree

[INFO] +- org.jdbi:jdbi3-spring5:jar:3.41.3:compile
[INFO] |  +- org.jdbi:jdbi3-core:jar:3.41.3:compile
[INFO] |  |  +- org.slf4j:slf4j-api:jar:1.7.36:compile
[INFO] |  |  \- io.leangen.geantyref:geantyref:jar:1.3.14:compile
[INFO] |  +- org.springframework:spring-beans:jar:5.3.30:compile
[INFO] |  +- org.springframework:spring-jdbc:jar:5.3.30:compile
[INFO] |  \- org.springframework:spring-tx:jar:5.3.30:compile
[INFO] \- org.springframework:spring-core:jar:6.0.13:compile
[INFO]    \- org.springframework:spring-jcl:jar:6.0.13:compile

仔細看,相依關係混雜著spring 5版與6版,最新版的Maven已經比舊版聰明許多,舊版會看到兩個不同的spring-core版本。 所以我們只要把pom.xml改成如下:

<project ...>
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>6.1.3</version>
    </dependency>
    <dependency>
      <groupId>org.jdbi</groupId>
      <artifactId>jdbi3-spring5</artifactId>
      <version>3.43.0</version>
    </dependency>
  </dependencies>
</project>

相依關係就變得如下:

[INFO] +- org.springframework:spring-jdbc:jar:6.0.13:compile
[INFO] |  +- org.springframework:spring-beans:jar:6.0.13:compile
[INFO] |  +- org.springframework:spring-core:jar:6.0.13:compile
[INFO] |  |  \- org.springframework:spring-jcl:jar:6.0.13:compile
[INFO] |  \- org.springframework:spring-tx:jar:6.0.13:compile
[INFO] \- org.jdbi:jdbi3-spring5:jar:3.41.3:compile
[INFO]    \- org.jdbi:jdbi3-core:jar:3.41.3:compile
[INFO]       +- org.slf4j:slf4j-api:jar:1.7.36:compile
[INFO]       \- io.leangen.geantyref:geantyref:jar:1.3.14:compile

原本Spring 5.3.30的版本都不見了,那是因為我們在jdbi之前先引入了spring-jdbc,由於spring-jdbc.6.0.13本身已有相依的spring-tx,所以Mavven到了處理jdbi3-spring5的相依關係時,發現已經引入了相關版本的artifact,便不會再次引入,所以讓Spring保持在6.0.13版。

當然,比較保險的方式,就是直接排除我們不要的artifact,再引進需要的jar

<project ...>
  <dependencies>
    <dependency>
      <groupId>org.jdbi</groupId>
      <artifactId>jdbi3-spring5</artifactId>
      <version>3.43.0</version>
        <exclusions>
          <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
          </exclusion>
          <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
          </exclusion>
          <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
          </exclusion>
          <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
          </exclusion>
        </exclusions>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>6.1.3</version>
    </dependency>
  </dependencies>
</project>

附帶一提,若需要下載所有相關的artifacts到本機端,請執行下列指令, 則會下載相依的Jars。

mvn dependency:copy-dependencies

另外,若要檢查專案是否採用最新版本的artifacts,可以執行下列指令,以出具版本報告,您再決定是否採用更新的版本。

mvn versions:display-dependency-updates

下列指令也可以出具外掛建議使用的版本報告(不一定是最新版)。

mvn versions:display-plugin-updates

不過因為versions-maven-plugin無法知道您使用的是哪個版本, 所以會列出一堆根據不同版本Maven的建議,若我們要限縮顯示的範圍。我們可以在pom.xml加本最低顯示的版本即可。

<project ... >
 <prerequisites>
   <maven>3.2.5</maven>
 </prerequisites>
</project>

版本管理的另一個課題是,我們如何保證,我們所開發用相關的jar(artifact)都是符合JDK版本需求?

例如JDK7用到專為JDK8所開發的artifact,就可能造成錯誤,例如openpdf

所以我們需要一個檢查機制,為此Maven推了一個所謂的Extension,可以套用於全域的專案,但往往我們可能在同一個開發環境開下發不同JDK版本的專案,所以我還是傾向透過外掛來執成此目的

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-enforcer-plugin</artifactId>
  <version>3.4.1</version>
  <executions>
    <execution>
      <id>enforce-java</id>
      <goals><goal>enforce</goal></goals>
      <configuration>
        <rules>
          <requireJavaVersion>
            <version>${maven.compiler.target}</version>
          </requireJavaVersion>
        </rules>
      </configuration>
    </execution>
  </executions>
</plugin>

是的,只要將maven.compiler.target設為1.7,當使用到不該用的Jar時,此外掛就會報錯並阻止Maven繼續進行。

最後一個問題是,多版本JDK的問題,Maven提供了maven-toolchains-plugin,但我照官方指示,執行 mvn toolchains:toolchain 很正常,就正當編譯時 enforcer 就一直報錯(我故意用比較低版本的JDK),好在Linux上面切換JDK版本非常簡易,所以暫時放棄。