是否可以在运行时指定System ClassLoader加载.class文件?

时间:2009-12-09 13:31:43

标签: java classpath classloader bytecode java-bytecode-asm

我正在为作业编写静态分析工具,它使用ASM库分析Java字节码。我们使用的ASM的一个部分需要(或者至少似乎要求)从ClassLoader加载类。

我们希望该工具能够分析.class文件,而不需要它们在类路径上。我们已经在运行时从指定目录加载.classes并使用InputStream读取它们。在大多数情况下,这对于ASM是可接受的。有一些类,例如SimpleVerifier,它们试图加载类。

在这种情况下,是否可以注册要加载的.class文件,以便调用Class.forName()来加载它们?或者有一种简单的方法来扩展ClassLoader以允许这个吗?


编辑:URLClassLoader上的信息很有用。不幸的是,在这种情况下使用Thread.currentThread().setContextClassLoader()到其实例并不起作用。我正在调用的库代码使用它在使用getClass().getClassLoader()实例初始化时检索的加载器。

当我设置URLClassLoader时,该类尚未初始化,所以我猜contextClassLoader不会加载该类。

我是否正确理解了答案?是否可以使用URLClassLoader加载第三方类?

6 个答案:

答案 0 :(得分:5)

几乎。

如果您在某处编译了类,则可以使用URLClassLoader加载它们。然后,您可以将此ClassLoader设置为当前线程的ClassLoader:Thread.setContextClassLoader(ClassLoader)

用户可以获取当前线程上下文类加载器并使用它来访问类定义。

答案 1 :(得分:5)

首先,ASM可以这样使用,它不会使用ClassLoader来获取有关类的信息。

ASM框架中有几个地方默认加载类,但所有这些地方都可以在您自己的子类中重写。脱颖而出:

    仅当使用ClassWriter.COMPUTE_FRAMES标志时才调用
  • ClassWriter.getCommonSuperClass()方法,并且可以覆盖该方法以不使用ClassLoader来获取有关类的信息。您可以在ClassWriterComputeFramesTest中找到引入ClassInfo抽象的示例
  • 同样,SimpleVerifier.isAssignableFrom()使用SimpleVerifier.getClass()方法,您可以覆盖后者并使用ClassInfo抽象来查找常见的超类型。如果我没有弄错的话,AspectWerkz项目在其类型模式匹配代码中实现了类似的功能。另请注意,有SimpleVerifier.setClassLoader()方法,如果您仍想加载自己的类,可以使用该方法。

另一方面,在Sun的JVM上,加载的类到达PermGen区域并且无法卸载,因此如果可以避免这种情况,那么仅为静态代码分析加载类不是一个好主意,尤其是工具将集成到一个长期过程中,例如IDE。

答案 2 :(得分:2)

据我所知,你不能在运行时扩展System类加载器,但你可以使用URLClassLoader从任意位置(jar或目录)动态加载类。

答案 3 :(得分:2)

您可以尝试在应用程序启动时设置“启动器”,创建URLClassLoader将类路径上的位置和您自己的.class位置传递给它,并从该类加载器启动应用程序。

SimpleVerifier加载URLClassLoader时,它也可以从其他位置加载类。

答案 4 :(得分:2)

是的,您可以使用URLClassLoader

我有一个测试,我在运行时加载该类。这个类不在类路径中(甚至在运行测试时也不存在),后来它被加载并且工作得很好。

这是代码。

void testHello() throws MalformedURLException, ClassNotFoundException {
    URL[] url = {
            new URL("file:/home/oreyes/testwork/")
    };

    try {
        new URLClassLoader(url).loadClass("Hello");
        throw new AssertionError("Should've thrown ClassNotFoundException");
    } catch ( ClassNotFoundException cnfe ){}


    c.process();// create the .class file 

    new URLClassLoader(url).loadClass("Hello");

    // it works!!
}

取自question

答案 5 :(得分:1)

我创建了自己的ClassLoader非常简单。

 /**
 * Used to hold the bytecode for the class to be loaded.
 */
private final static ThreadLocal<byte[]> BYTE_CODE = new ThreadLocal<byte[]>();

@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
    final byte[] bytes = BYTE_CODE.get();
    if (null == bytes) {
        throw new ClassNotFoundException(name);
    }
    return this.defineClass(null, bytes, 0, bytes.length);
}