Java 从项目中删除未使用的 jars
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19099121/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
remove unused jars from project
提问by flowerpot
What is the easiest way (tool ?) to remove unused jars from my java (ant ) project. Our project has become really huge, and we want to do a clean up. There are several jars that are added to the classpath, but not all are used for compile/run. Is there a way to identify the unnecessary jars by running some utility from command line?
Note: we do not want to follow the tedious process of removing one or more jars, then compile/run to test if those are required or not.
从我的 java (ant) 项目中删除未使用的 jar 的最简单方法(工具?)是什么。我们的项目变得非常庞大,我们想要进行清理。有几个 jars 被添加到类路径中,但并不是所有的 jars 都用于编译/运行。有没有办法通过从命令行运行一些实用程序来识别不必要的 jars?
注意:我们不想遵循删除一个或多个 jar 的繁琐过程,然后编译/运行以测试是否需要这些。
采纳答案by flowerpot
This is what I did finally
I used JBOSS TattleTale (http://www.jboss.org/tattletale) to identify unused jars at compile time (It reported 17 jars as unused).
Then for each of the jar in that list, I did a string search on my project to find if the highest package level of the jar was used anywhere (this is an attempt to see if any class belonging to this jar was loaded using reflection).
This way I was able to successfully eliminate 6 jars from my project.
Since, number of unused jars at compile time was small, this approach was quick.
这就是我最后所做的,
我使用 JBOSS TattleTale ( http://www.jboss.org/tattletale) 在编译时识别未使用的 jar(它报告 17 个 jar 为未使用)。
然后对于该列表中的每个 jar,我对我的项目进行了字符串搜索,以查找是否在任何地方使用了该 jar 的最高包级别(这是尝试查看是否使用反射加载了属于该 jar 的任何类) .
通过这种方式,我能够成功地从我的项目中消除 6 个罐子。
由于编译时未使用的 jar 数量很少,因此这种方法很快。
回答by Daniel Kaplan
If there's a better solution to this, I'd love to hear it.
如果有更好的解决方案,我很乐意听到。
The problem is that even if a jar isn't needed to compile, it could be needed to run. And this "need" could be transitive. EG: A jar you use needs a jar you don't use and only at runtime. As is the nature of runtime errors, they'll only reveal themselves when you try to execute the code. Worst case, that may not occur until you're running in production.
问题是,即使不需要 jar 来编译,也可能需要它来运行. 而这种“需要”可能是传递性的。EG:您使用的 jar 需要一个您不使用且仅在运行时使用的 jar。正如运行时错误的性质一样,它们只会在您尝试执行代码时显示出来。最坏的情况是,在您在生产中运行之前可能不会发生这种情况。
The best solution I know of is exactly what you don't want to do: "removing one or more jars, then compile/run to test if those are required or not".
我所知道的最佳解决方案正是您不想做的:“删除一个或多个 jar,然后编译/运行以测试是否需要这些”。
回答by Peerapat A
Remove -> Test -> Remove -> Test -> Remove -> Hope you enjoy :)
删除 -> 测试 -> 删除 -> 测试 -> 删除 -> 希望你喜欢 :)
Change project to maven and select only jar you wanna use. For me this is the easiest way.
将项目更改为 maven 并仅选择您想要使用的 jar。对我来说,这是最简单的方法。
回答by Jayan
As noted by tieTYT in his answer, many jars are needed only at compile time. (for example jdbc implementation jars)
正如 tieTYT 在他的回答中所指出的,许多 jar 仅在编译时才需要。(例如 jdbc 实现 jars)
Another approach could be to write a java agent and collect all classnames. You can then map these classnames to jar and see if any jars are not needed.
另一种方法可能是编写一个 Java 代理并收集所有类名。然后,您可以将这些类名映射到 jar 并查看是否不需要任何 jar。
Sample agent
样品代理
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
Build.xml... 用于蚂蚁
<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>
Another approach we tried in windowswas using the fact that the jars get locked when classes are loaded. Run the application and try to delete from runtime area. If it was used, delete should fail. Not sure how safe this is- I know that it does not work on linux etc, the files can be deleted without problem.
我们在Windows中尝试的另一种方法是利用在加载类时 jar 被锁定的事实。运行应用程序并尝试从运行区中删除。如果使用了它,删除应该会失败。不确定这有多安全 - 我知道它在 linux 等上不起作用,可以毫无问题地删除文件。