我正在为作业编写静态分析工具,它使用ASM库分析Java字节码。我们使用的ASM的一个部分需要(或者至少似乎要求)从ClassLoader加载类。
我们希望该工具能够分析.class文件,而不需要它们在类路径上。我们已经在运行时从指定目录加载.classes并使用InputStream读取它们。在大多数情况下,这对于ASM是可接受的。有一些类,例如SimpleVerifier
,它们试图加载类。
在这种情况下,是否可以注册要加载的.class文件,以便调用Class.forName()
来加载它们?或者有一种简单的方法来扩展ClassLoader以允许这个吗?
编辑:URLClassLoader
上的信息很有用。不幸的是,在这种情况下使用Thread.currentThread().setContextClassLoader()
到其实例并不起作用。我正在调用的库代码使用它在使用getClass().getClassLoader()
实例初始化时检索的加载器。
当我设置URLClassLoader时,该类尚未初始化,所以我猜contextClassLoader不会加载该类。
我是否正确理解了答案?是否可以使用URLClassLoader加载第三方类?
答案 0 :(得分:5)
几乎。
如果您在某处编译了类,则可以使用URLClassLoader加载它们。然后,您可以将此ClassLoader设置为当前线程的ClassLoader:Thread.setContextClassLoader(ClassLoader)
用户可以获取当前线程上下文类加载器并使用它来访问类定义。
答案 1 :(得分:5)
首先,ASM可以这样使用,它不会使用ClassLoader来获取有关类的信息。
ASM框架中有几个地方默认加载类,但所有这些地方都可以在您自己的子类中重写。脱颖而出:
另一方面,在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);
}