引言

java 项目中常用 maven 工具来进行工程管理,但经常遇到的一个问题是生成的 jar 包越来越大,编译一次工程越来越慢。怎么有效地去除冗余依赖,给 jar 包进行瘦身,是一项必备技能

将环境中已包含的依赖包的 [scope] 设置为 provided

pom 中依赖的部分包可能==在你程序运行环境中已经包含==,此时应该将依赖包的 scope 设置为 provided。如 protobuf 包如在环境中已包含,则应设置为:

<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java</artifactId>
    <version>${protobuf.version}</version>
    <scope>provided</scope>
</dependency>

删除未使用依赖

在pom文件配置时可能加入的某些依赖包并没有真正被使用到,那么有没有一种有效的方式找到没有被使用到的依赖包呢?答案是Apache Maven Dependency Plugin。

安装Apache Maven Dependency Plugin插件并运行mvn dependency:analyze命令来分析项目的依赖关系,并确定哪些依赖是:使用且声明的、使用且未声明的和未使用且声明的。将未使用且声明的的依赖从pom文件中去除即可。

20220423120820.png

Used undeclared dependencies found

这个是指某些依赖的包在代码中有用到它的代码,但是它并不是直接的依赖(就是说没有在 pom 中直接声明),是通过引入传递下来的包。

举个例子:

projectpom 中声明了 A.jar 的依赖(没有声明 B.jar 的依赖) A.jar 的依赖关系:A.jar -> B.jar 通过 mvn dependency:analyze 出现 [WARNING] Used undeclared dependencies found: B.jar 就说明 project 中的代码用到了 B.jar 的代码 这个时候你就可以把 B.jar 直接声明在 pom 中

Unused declared dependencies found

这个是指我们在 pom 中声明了依赖,但是在实际代码中==并没有用到这个包==!也就是多余的包。 这个时候我们就可以把这个依赖从 pom 中剔除。

但是这里我们需要注意:

这里说的实际代码没有用到指的是在 main/java 和 test 里没有用的但是并不是意味着真的没有用到这些包,有可能配置文件中引用或者其他扩展点自动加载这些包,所以我们在删除依赖的时候一定要小心,做好备份,因为这类引用 maven 是分析不出来的。

去除重复依赖

在pom文件中有些依赖可能在中被重复配置,或者父子项目配置中可能同一个依赖包被重复配置。可通过Apache Maven Dependency Plugin插件并运行mvn dependency:analyze-duplicate命令来检查项目的重复依赖,然后删除重复依赖项即可。20220423120900.png

解决依赖冲突

项目中不同的依赖包可以同时依赖另一个包,而这个嵌套依赖的包可能版本不一致,这可能导致程序无法正常运行,或者运行过程中产生一些很诡异的问题。

那如何方便地找到所有的依赖冲突项并解决呢?在 intellij 中安装 maven helper 插件可快速找出有冲突的包。如何解决可以参考IDEA 插件整理

某些场景下 exclusion 冲突的不同版本的依赖包会导致程序无法执行,可能的原因是该依赖包无法在其嵌套包的其他版本下正常运行。此时可能需要尝试找一个新版本的依赖包使其依赖的嵌套包能与其他依赖包达到兼容。

去除指定文件

如果采取了上面几个步骤后还是无法达到jar包有效瘦身的目标,那就只能使用最终大杀器:将不需要的指定文件或者文件夹从最终的jar包中移除。之所以有不需要的文件被打到jar包,一方面可能工程中包含了一些非代码的工程文件,如项目文档等;另一方面可能你依赖的jar包中包含了不需要的冗余文件。

使用maven-shade-plugin插件可将匹配特定条件的文件从jar包中移除。如下所示,配置exclude项可从最终的jar包中去除匹配特定条件的文件或文件夹(可以是配置文件,也可以是代码文件)。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.4.3</version>
    <executions>
        <execution>
            <id>uber-jar</id>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <finalName>${project.artifactId}-${project.version}-jar-with-dependencies</finalName>
                <filters>
                    <filter>
                        <artifact>*:* </artifact>
                        <excludes>
                            <exclude>LICENSE</exclude>
                            <exclude>META-INF/*.SF</exclude>
                            <exclude>META-INF/*.DSA</exclude>
                            <exclude>META-INF/*.RSA</exclude>
                        </excludes>
                    </filter>
                </filters>
            </configuration>
        </execution>
    </executions>
</plugin>

引用