从我的java(ant)项目中删除未使用的jar的最简单方法(工具?)是什么?我们的项目变得非常庞大,我们想要做一个清理工作。有几个jar添加到类路径中,但并非所有jar都用于编译/运行。有没有办法通过从命令行运行一些实用工具来识别不必要的罐子?
注意:我们不想按照删除一个或多个罐子的繁琐过程,然后编译/运行来测试是否需要这些罐子。
答案 0 :(得分:11)
这是我最后做的
我使用JBOSS TattleTale(http://www.jboss.org/tattletale)在编译时识别未使用的罐子(它报告了17罐未使用)。
然后对于该列表中的每个jar,我在我的项目上进行了字符串搜索,以查找是否在任何地方使用了jar的最高包级别(这是尝试查看属于此jar的任何类是否是使用反射加载)。
这样我就可以成功地从我的项目中消除6个罐子
由于编译时未使用的罐子数量很少,这种方法很快。
答案 1 :(得分:4)
如果有更好的解决方案,我很乐意听到。
问题是即使编译不需要jar,也可能需要运行。这种“需要”可能是传递性的。 EG:你使用的jar需要一个你不使用的jar,并且只在运行时使用。正如运行时错误的本质一样,它们只会在您尝试执行代码时显示自己。最坏的情况,直到你在生产中运行才可能发生。
我所知道的最佳解决方案正是您不想做的事情:“删除一个或多个罐子,然后编译/运行以测试是否需要这些罐子。”
答案 2 :(得分:2)
删除 - >测试 - >删除 - >测试 - >删除 - >希望你喜欢:)
将项目更改为maven并仅选择您想要使用的jar。对我来说,这是最简单的方法。
答案 3 :(得分:1)
正如tieTYT在他的回答中所指出的那样,只有在编译时才需要许多罐子。 (例如jdbc实现jar)
另一种方法可能是编写java代理并收集所有类名。然后,您可以将这些类名映射到jar,并查看是否需要任何jar。
样本代理
package com;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
public class NameAgent {
public static void premain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new Tranformer(), true);
}
static class Tranformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
System.out.println("loading-class:" + className);
return classfileBuffer;
}
}
}
Build.xml ... for ant
<project name="namedump" default="dist" basedir=".">
<property name="src" value="src"/>
<property name="build" value="build"/>
<property name="dist" value="dist"/>
<target name="init">
<mkdir dir="${build}"/>
<mkdir dir="${dist}"/>
</target>
<target name="compile" depends="init">
<javac srcdir="${src}" destdir="${build}" optimize="true" includeantruntime="false"/>
</target>
<target name="dist" depends="compile">
<jar jarfile="${dist}/namecollector.jar">
<fileset dir="${build}"/>
<manifest >
<attribute name="Premain-Class" value="com.NameAgent" />
<attribute name="Can-Redefine-Classes" value="true" />
<attribute name="Can-Retransform-Classes" value="true" />
</manifest>
</jar>
<pathconvert property="absdist" dirsep="/">
<path location="${dist}"/>
</pathconvert>
<echo>
To use, add the following to the JVM command-line options.
-javaagent:${absdist}/namecollector.jar
</echo>
</target>
<target name="clean">
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
我们在 windows 中尝试的另一种方法是使用以下事实:在加载类时,jar会被锁定。运行应用程序并尝试从运行时区域删除。如果使用它,删除应该失败。不确定这是多么安全 - 我知道它在linux等上不起作用,文件可以毫无问题地删除。