不需要的Jar依赖 loosejar和maven工具实践分析
mvn 工具依赖检查
在很多的项目中,往往都存在一些冗余的JAR包依赖,可能是某次的测试加入但是之后没有删除,可能是引用传递的依赖,也可能是历史代码但在后面升级后已经有其他的替换方案了,可没有剔除原先的依赖等等情况。想要更好的提升构建速度以及减少依赖存在漏洞的可能性,那么就需要从源头出发,优化项目相关的依赖JAR,剔除一些无用的依赖。我们可以通过mvn dependency:analyze的方式去分析依赖情况。
mvn dependency:analyze
使用该命令对项目进行了扫描分析,以下是分析结果,截取其中一部分
[INFO] --- maven-dependency-plugin:3.2.0:analyze (default-cli) --- [WARNING] Used undeclared dependencies found: [WARNING] org.springframework:spring-beans:jar:5.3.21:compile [WARNING] org.springframework:spring-jdbc:jar:5.3.21:compile [WARNING] org.springframework.boot:spring-boot:jar:2.6.9:compile [WARNING] org.springframework.security:spring-security-config:jar:5.6.6:compile [WARNING] org.springframework.cloud:spring-cloud-openfeign-core:jar:3.1.1:compile [WARNING] org.slf4j:slf4j-api:jar:1.7.36:compile [WARNING] xml-apis:xml-apis:jar:1.0.b2:compile [WARNING] jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile [WARNING] org.springframework.boot:spring-boot-test:jar:2.6.9:test [WARNING] org.junit.jupiter:junit-jupiter-api:jar:5.8.2:test [WARNING] org.springframework.amqp:spring-amqp:jar:2.4.6:compile [WARNING] com.alibaba:druid:jar:1.2.9:compile [WARNING] Unused declared dependencies found: [WARNING] org.springframework.boot:spring-boot-starter-security:jar:2.6.9:compile [WARNING] org.thymeleaf.extras:thymeleaf-extras-springsecurity5:jar:3.0.4.RELEASE:compile [WARNING] org.springframework.boot:spring-boot-starter-thymeleaf:jar:2.6.9:compile [WARNING] org.springframework.boot:spring-boot-starter-web:jar:2.6.9:compile [WARNING] org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.41:compile [WARNING] org.springframework.boot:spring-boot-configuration-processor:jar:2.6.9:compile [WARNING] org.mybatis.spring.boot:mybatis-spring-boot-starter:jar:2.1.4:compile [WARNING] org.springframework.boot:spring-boot-starter-aop:jar:2.6.9:compile [WARNING] org.springframework.boot:spring-boot-devtools:jar:2.6.9:compile [WARNING] org.springframework.boot:spring-boot-starter-test:jar:2.6.9:test [WARNING] org.springframework.boot:spring-boot-starter-data-redis:jar:2.6.9:compile [WARNING] redis.clients:jedis:jar:3.9.0:compile
如上图所示,可以看到俩行主要的提示
【Used undeclared dependencies found】
这个是指某些依赖的包在代码中有用到它的代码,但是它并不是直接的依赖(就是说没有在pom中直接声明),是通过引入传递下来的包。
即项目在pom中声明了A.jar的依赖(没有声明B.jar的依赖) ,但是A自己的依赖中引入了B.jar,说明project中的代码用到了B.jar的代码 这个时候你就可以把B.jar直接声明在pom中。
【Unused declared dependencies found】
这个是指我们在pom中声明了依赖,但是在实际代码中并没有用到这个包,也就是多余的包。这个时候我们就可以把这个依赖从pom中剔除。
运行时依赖检查loosejar工具
安装配置详细github官网地址
工作原理
loosejar的工作原理是利用classloader。由于应用在执行的时候,用到哪个类,classloader就会把这个类的.class文件载入到jvm中,然后生成一个class对象。然后再利用反射就能够执行这个类的方法了,因此有哪些.class文件被载入了,classloader能够清楚的知晓,利用这个特性,便可知道jar包中类的实际使用情况,以及应用中jar包的实际使用情况了。
依赖扫描
直接在本地的IDEA启动Java项目,并且指定启动VM参数
【1】在项目启动成功后,通过jconsole工具查看当前类加载情况,并点击summary 查看类加载,将其内容复制到文本工具中。
【2】运行并测试项目中的相关功能,在正常运行一段时间后,再次通过jconsole工具查看当前类加载情况
【3】搜索关键词AppClassLoader,仅比较AppClassLoader下面的类加载信息。
【4】将两次的分析结果记录下来,后面会进行分析比较。
Maven Helper工具使用
在进行依赖检查的时候,建议IDEA安装Maven Helper插件,在进行依赖分析以及排除的时候可以通过该工具帮助我们定位以及一键排除。
结果分析
针对上面两次的扫描结果这里做简单的场景分析
【1】下面显示elasticsearch-geo依赖在两次扫描都没有被使用,结合目前的项目来看,确实在ES方面没有使用到geo相关的功能。
【2】下面针对第二次扫描结果进行了0.00%引用依赖的计数查找,大概有188个,相对于mvn dependency:analyze来说,它的扫描结果更加广泛,同时loosejar基于运行时的结果实时分析,比静态分析也更加全面准确。
【3】通过下图可以看到,在第二次扫描时原先被判定未引用的现在有依赖关系了,所以在使用该工具时一定要注意全面的测试,在判定某个特定的依赖是否要删除,做好检查。
【4】对于该工具,可以将它集成到日常的开发中去,在保持运行一段时间后在进行依赖使用的分析,在根据其结果合理的去除或者exclude相关的子依赖。
自定义配置
loosejar提供了两个自定义配置,可以通过设置Java系统属性的方式去配置:
loosejar.format:这是一个非强制属性,可用于指定输出格式,目前支持csv或verbal 。此配置还影响通过JMX控制台提取的结果的输出格式。
示例:
verbal格式:
Jar: D:\maven\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar Utilization: 10.71% - loaded 3 of 28 classes.
csv格式:
"jdk.internal.loader.ClassLoaders$AppClassLoader","D:\maven\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar","10.71%","3","28"
loosejar.outputFile:这是一个非强制属性,可用于将结果提取到文件中。如果未指定此选项,loosejar将结果打印到控制台(System.out)。此配置仅在应用程序关闭时应用。
注意:在使用IDEA关闭项目时点击一次stop即可,如果多次点击快速停止可能无法捕获信息。
【参考配置】
指定输出自定义文件并且指定输出格式为csv
-javaagent:E:\test\loosejar-1.2.0.jar -Dloosejar.outputFile=E:\test\demo.txt -Dloosejar.format=csv
【1】上面的工具只是帮助我们分析了依赖,但是注意并不是说完全就可以确定对应的依赖可以直接剔除。在决定剔除之前和之后要有仔细的核对和检查,保证不会有影响。在之前的一次依赖排除中就遇到过某些poi相关的组件被排除了,启动时正常但是在运行特定功能时运行报错。还有一些网络通信的组件,这些往往都不是显示声明,对于这种运行时的组件一定要做好测试。
【2】在上面分析之后,可以通过mvn dependency:tree或者IDEA的maven依赖插件Maven Helper去分析下对应的依赖情况,做下核对检查。
【3】使用loosejar这种运行时跟踪检测的工具相对来说比其他静态分析的工具分析的结果要更加精确也更加全面。
【4】对于loosejar更适合将它集成到日常的开发中或者集成到研发测试环境,在运行过程中做好依赖信息的记录,并在运行一段时间后进行依赖的对比分析,根据分析结果选择性的排除一些不需要的依赖信息。
#Java开发#