从项目中删除未使用的罐子

时间:2013-09-30 16:23:41

标签: java ant jar


从我的java(ant)项目中删除未使用的jar的最简单方法(工具?)是什么?我们的项目变得非常庞大,我们想要做一个清理工作。有几个jar添加到类路径中,但并非所有jar都用于编译/运行。有没有办法通过从命令行运行一些实用工具来识别不必要的罐子? 注意:我们不想按照删除一个或多个罐子的繁琐过程,然后编译/运行来测试是否需要这些罐子。

4 个答案:

答案 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等上不起作用,文件可以毫无问题地删除。