4

使用 Maven Enforcer 插件检查依赖

 2 years ago
source link: https://www.diguage.com/post/use-maven-enforcer-plugin-to-check-dependencies/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

使用 Maven Enforcer 插件检查依赖

2022-03-29
使用 Maven Enforcer 插件检查依赖

最近公司项目要对一些内部依赖做集中升级。为此,D瓜哥发布了一个 BOM(BOM stands for Bill Of Materials),用于规范项目依赖及版本。

但是升级后,效果不理想,检查发现还是有不少依赖的版本依然不符合要求。经同事提醒,可以使用 Apache Maven Enforcer 来做规范检查,测试一下效果确实不错。

将 Apache Maven Enforcer 和 Extra Enforcer Rules 的文档大致巴拉了一遍之后,根据项目的实际情况,挑选出来可用规则如下:

比较有用的几个规则

  1. bannedDependencies – 排除不需要的依赖,引入需要的依赖。

  2. banDuplicatePomDependencyVersions – 防止依赖重复声明。

  3. dependencyConvergence – 确保所有依赖收敛到相同的版本。也可以考虑加入。

  4. reactorModuleConvergence – 多模块开发时,确保父子模块的版本是一致的。

  5. requireJavaVersion – 检查 JDK 的版本

  6. requireMavenVersion – 检查 Maven 的版本

  7. requireReleaseVersion – 这个可以通过激活生产环境的 profile 来启用该规则,保证发布的不是快照版。

  8. requireUpperBoundDeps – 确保直接引用的依赖不比间接解析出来的依赖版本低。感觉这个也挺有用,但是使用方式还没搞清楚。实例有些模糊。

  9. banDuplicateClasses – 检查重复类定义。可以避免一些特殊情况。

  10. requirePropertyDiverges – 确保项目定义的属性与依赖中包含的属性不重复。

  11. enforceBytecodeVersion – 确保使用的字节码版本不高于指定版本。

  12. banCircularDependencies – 确保没有循环依赖。

  13. requireEncoding – 指定项目字符集。

D瓜哥把上面的规则几乎全部试用了一遍,把发现的一些需要特别注意的地方标注记录一下吧:

  1. banDuplicateClasses — 这个插件还是很棒的。使用的时候,成功检查出废弃不用的依赖(废弃依赖被收入到另外一个依赖中了。)。不过,也发现一些问题,项目中使用了 netty-all 及 Netty 的其他模块依赖。但是,并没有检查出来,感觉是项目代码有直接依赖的重复类才会被检测出来。

  2. requireUpperBoundDeps — 开启这个检查时,发现间接引用了 commons-lang:commons-lang:2.6,但是项目直接声明的依赖是 commons-lang:commons-lang:2.5,就直接报错了。私以为这个检查规则还是很赞的。但是,因为我们的项目中有有依赖 Gson 1.X,也有 Gson 2.X 的,而且这两个版本在处理父子类有相同字段时的存在抛异常的差异,所以无法启用,实在可惜。

  3. reactorModuleConvergence –- 多模块开发时,确保父子模块的版本是一致的。这个规则还是很赞的。但是,因为我测试的模块不存在这个问题,所以,没有触发报警。

  4. requirePropertyDiverges — 本想启用这个规则,看了一下配置,着实麻烦,而且不是全局检查,似乎是检查指定配置项,感觉不是很满意。没有启用。

  5. enforceBytecodeVersion — 检查字节码版本。这个是不超过上限,我是想检查下限,所以没有启用。反思:在写这个文章时,又思考了一下,检查下限是有问题的,一些陈旧的依赖就不能使用了。但是这些依赖是没有问题的。

  6. banCircularDependencies — 这个规则似乎 Maven 已经内置了,以前遇到过这样的场景,Maven 直接报错了。所以,就没有启用这个规则。

  7. requireEncoding — 这个规则非常棒。在试用过程中发现,它会把存 ASCII 字符的 UTF-8 文件判定为 US-ASCII 编码。没有找到好的办法来解决这个问题。所以,可惜没有启用。

在测试完上面这些规则时,同事还提醒有个漏洞检查的规则也可以用一下,然后就使用了一下。结果如下:

这是 Sonatype 提供的插件,配置如下:

<!-- D瓜哥 · https://www.diguage.com 出品 -->
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-enforcer-plugin</artifactId>
      <dependencies>
        <dependency>
          <groupId>org.sonatype.ossindex.maven</groupId>
          <artifactId>ossindex-maven-enforcer-rules</artifactId>
        </dependency>
      </dependencies>
      <executions>
        <execution>
          <id>vulnerability-checks</id>
          <phase>validate</phase>
          <goals>
            <goal>enforce</goal>
          </goals>
          <configuration>
            <rules>
              <banVulnerable implementation="org.sonatype.ossindex.maven.enforcer.BanVulnerableDependencies"/>
            </rules>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

启用这个插件后,在一个项目中检查出非常多的漏洞,挑选两个来重点说明一下:

  1. mysql.mysql-connector-java — MySQL JDBC 5.1.49 竟然有漏洞,这是始料未及的。原来在 Maven Repository 中没有提示有漏洞。今天又检查了一下,发现确实有漏洞。

  2. [CVE-2019-20444 HttpObjectDecoder.java in Netty before 4.1.44 allows an HTTP header that lacks a…​^] — 提示 Netty 有漏洞,在说明中也提示是 4.1.44 版本之前。但是,项目依赖的明明是 4.1.75.Final,还提示报错。这就有点差强人意了。

插件还给出了每个漏洞的链接信息(上面两个网址,就是漏洞信息),想保留这个检查,但是它不知道只检查不失败,最后只能放弃。

最后测试,最后保留的规则如下(删去了公司内部一些依赖):

<!-- D瓜哥 · https://www.diguage.com 出品 -->
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-enforcer-plugin</artifactId>
  <version>3.0.0</version>
  <dependencies>
    <dependency>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>extra-enforcer-rules</artifactId>
      <version>1.5.1</version>
    </dependency>
    <!-- <dependency>-->
    <!--   <groupId>org.sonatype.ossindex.maven</groupId>-->
    <!--   <artifactId>ossindex-maven-enforcer-rules</artifactId>-->
    <!--   <version>3.2.0</version>-->
    <!-- </dependency>-->
  </dependencies>
  <executions>
    <execution>
      <!-- 检测 Maven 版本 -->
      <!-- https://maven.apache.org/enforcer/enforcer-rules/requireMavenVersion.html -->
      <id>enforce-versions</id>
      <phase>install</phase>
      <goals>
        <goal>enforce</goal>
      </goals>
      <configuration>
        <rules>
          <requireMavenVersion>
            <version>3.5.0</version>
          </requireMavenVersion>
          <requireJavaVersion>
            <version>1.8</version>
            <message>
              <![CDATA[You are running an older version of Java. This application requires at least JDK 1.8.]]>
            </message>
          </requireJavaVersion>
        </rules>
      </configuration>
    </execution>
    <execution>
      <!-- 检查依赖重复声明的情况 -->
      <!-- https://maven.apache.org/enforcer/enforcer-rules/banDuplicatePomDependencyVersions.html -->
      <id>enforce-no-duplicate-declared-dependencies</id>
      <goals>
        <goal>enforce</goal>
      </goals>
      <configuration>
        <rules>
          <banDuplicatePomDependencyVersions/>
        </rules>
      </configuration>
    </execution>
    <execution>
      <!-- 检查依赖版本情况 -->
      <!-- https://maven.apache.org/enforcer/enforcer-rules/dependencyConvergence.html -->
      <id>enforce-dependencyConvergence</id>
      <goals>
        <goal>enforce</goal>
      </goals>
      <configuration>
        <rules>
          <dependencyConvergence/>
        </rules>
      </configuration>
    </execution>
    <execution>
      <!-- 确保父子模块的版本是一致的。 -->
      <!-- https://maven.apache.org/enforcer/enforcer-rules/reactorModuleConvergence.html -->
      <id>enforce-reactorModuleConvergence</id>
      <goals>
        <goal>enforce</goal>
      </goals>
      <configuration>
        <rules>
          <reactorModuleConvergence>
            <message>父子模块的版本必须一直。</message>
            <ignoreModuleDependencies>true</ignoreModuleDependencies>
          </reactorModuleConvergence>
        </rules>
        <fail>true</fail>
      </configuration>
    </execution>
    <execution>
      <!-- 确保直接引用的依赖不比间接解析出来的依赖版本低。 -->
      <!-- https://maven.apache.org/enforcer/enforcer-rules/requireUpperBoundDeps.html -->
      <id>enforce-requireUpperBoundDeps</id>
      <goals>
        <goal>enforce</goal>
      </goals>
      <configuration>
        <rules>
          <requireUpperBoundDeps>
          </requireUpperBoundDeps>
        </rules>
      </configuration>
    </execution>
    <!-- <execution>-->
    <!--   <!– 检测文件字符集都是 UTF-8 –>-->
    <!--   <!– https://www.mojohaus.org/extra-enforcer-rules/requireEncoding.html –>-->
    <!--   <id>require-utf-8</id>-->
    <!--   <goals>-->
    <!--     <goal>enforce</goal>-->
    <!--   </goals>-->
    <!--   <configuration>-->
    <!--     <rules>-->
    <!--       <requireEncoding>-->
    <!--         <encoding>UTF-8</encoding>-->
    <!--         <includes>src/main/resources/,src/test/resources/</includes>-->
    <!--       </requireEncoding>-->
    <!--     </rules>-->
    <!--     <fastFail>false</fastFail>-->
    <!--   </configuration>-->
    <!-- </execution>-->
    <execution>
      <!-- 检测依赖 -->
      <!-- https://maven.apache.org/enforcer/enforcer-rules/bannedDependencies.html -->
      <id>enforce-banned-dependencies</id>
      <goals>
        <goal>enforce</goal>
      </goals>
      <configuration>
        <rules>
          <!-- lombok -->
          <bannedDependencies>
            <searchTransitive>true</searchTransitive>
            <excludes>
              <exclude>org.projectlombok:lombok</exclude>
            </excludes>
            <includes>
              <include>org.projectlombok:lombok:*:*:provided</include>
            </includes>
            <message>
              <![CDATA[Lombok 不能在 runtime 被引入!请使用 provided。]]>
            </message>
          </bannedDependencies>

          <!-- log4j -->
          <bannedDependencies>
            <searchTransitive>true</searchTransitive>
            <excludes>
              <exclude>log4j</exclude>
              <exclude>org.slf4j:slf4j-log4j12</exclude>
            </excludes>
            <message><![CDATA[不能使用 Log4j。]]></message>
          </bannedDependencies>

          <!-- commons log -->
          <bannedDependencies>
            <searchTransitive>true</searchTransitive>
            <excludes>
              <exclude>commons-logging</exclude>
            </excludes>
            <message><![CDATA[不能使用 commons logging。]]></message>
          </bannedDependencies>

          <!-- jdk log -->
          <bannedDependencies>
            <searchTransitive>true</searchTransitive>
            <excludes>
              <exclude>org.slf4j:slf4j-jdk14</exclude>
            </excludes>
            <message><![CDATA[不能使用 jdk log。]]></message>
          </bannedDependencies>

          <!-- logback 1.2.0+ -->
          <bannedDependencies>
            <searchTransitive>true</searchTransitive>
            <excludes>
              <exclude>ch.qos.logback:*:[,1.2.0):jar</exclude>
            </excludes>
            <message><![CDATA[必须使用 logback 1.2.0+。]]></message>
          </bannedDependencies>

          <!-- slf4j 1.7.25+ -->
          <bannedDependencies>
            <searchTransitive>true</searchTransitive>
            <excludes>
              <exclude>org.slf4j:*:[,1.7.25):jar</exclude>
            </excludes>
            <message><![CDATA[必须使用 slf4j 1.7.25+。]]></message>
          </bannedDependencies>

          <!-- Javassist 3.24.0-GA+ -->
          <bannedDependencies>
            <searchTransitive>true</searchTransitive>
            <excludes>
              <exclude>org.javassist:javassist:[,3.24.0-GA):jar</exclude>
              <exclude>javassist:javassist</exclude>
            </excludes>
            <message><![CDATA[必须使用 Javassist 3.24.0-GA+。]]></message>
          </bannedDependencies>

          <!-- Jakarta Validation -->
          <bannedDependencies>
            <searchTransitive>true</searchTransitive>
            <excludes>
              <exclude>javax.validation:validation-api:[,2.0.1.Final):jar</exclude>
              <exclude>org.hibernate.validator:hibernate-validator:[,6.1.5.Final):jar</exclude>
              <exclude>org.hibernate.validator:hibernate-validator-annotation-processor:[,6.1.5.Final):jar</exclude>
              <exclude>org.hibernate:hibernate-validator</exclude>
            </excludes>
            <message>
              <![CDATA[必须使用 jakarta.validation:jakarta.validation-api:2.0.1+ 和 Hibernate Validator 6.1.5.Final+(org.hibernate.validator:hibernate-validator:6.1.5.Final 和 org.hibernate.validator:hibernate-validator-annotation-processor:6.1.5.Final)。不能使用 javax.validation:validation-api 和 org.hibernate:hibernate-validator。]]>
            </message>
          </bannedDependencies>
        </rules>
        <fail>true</fail>
      </configuration>
    </execution>
    <execution>
      <!-- 检测重复类定义。 -->
      <!-- https://www.mojohaus.org/extra-enforcer-rules/banDuplicateClasses.html -->
      <id>enforce-ban-duplicate-classes</id>
      <goals>
        <goal>enforce</goal>
      </goals>
      <configuration>
        <rules>
          <banDuplicateClasses>
            <scopes>
              <scope>compile</scope>
            </scopes>
            <findAllDuplicates>true</findAllDuplicates>
            <ignoreWhenIdentical>true</ignoreWhenIdentical>
            <ignoreClasses>
              <ignoreClass>module-info</ignoreClass>
              <ignoreClass>org.apache.commons.logging.*</ignoreClass>
            </ignoreClasses>
          </banDuplicateClasses>
        </rules>
        <fail>true</fail>
      </configuration>
    </execution>
    <!-- <execution>-->
    <!--   <!– 依赖漏洞检查 –>-->
    <!--   <id>vulnerability-checks</id>-->
    <!--   <goals>-->
    <!--     <goal>enforce</goal>-->
    <!--   </goals>-->
    <!--   <configuration>-->
    <!--     <rules>-->
    <!--       <banVulnerable implementation="org.sonatype.ossindex.maven.enforcer.BanVulnerableDependencies"/>-->
    <!--     </rules>-->
    <!--   </configuration>-->
    <!-- </execution>-->
  </executions>
</plugin>

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK