我正在动态加载jar并尝试在jar中创建给定类的新实例。为了使事情变得更有趣,这个罐子是从Leiningen clojure项目编译而来的。我创建了一个自定义字节类加载器:
private static class ByteClassLoader extends ClassLoader {
private final Map<String, byte[]> classDataMap;
public ByteClassLoader() {
this.classDataMap = new HashMap<>();
}
public void addClassData(String className, byte[] bytes) {
classDataMap.put(className, bytes);
}
@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
byte[] classData = classDataMap.get(name);
if (classData != null)
return defineClass(name, classData, 0, classData.length);
return super.findClass(name);
}
}
现在我从自定义类加载器中获取我感兴趣的类,并尝试创建一个新实例。
Class<?> myClass = byteClassLoader.findClass("com.example.Foo");
myClass.newInstance();
但这会抛出一个未找到文件的异常:
Caused by: java.io.FileNotFoundException: Could not locate some/namespace.class or some/namespace.clj on classpath:
at clojure.lang.RT.load(RT.java:443)
at clojure.lang.RT.load(RT.java:411)
at clojure.core$load$fn__5018.invoke(core.clj:5530)
at clojure.core$load.doInvoke(core.clj:5529)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.lang.Var.invoke(Var.java:407)
at com.example.Foo.<clinit>(Unknown Source)
... 33 more
似乎对新实例的调用不了解自定义类加载器。这听起来像是对错误的正确理解吗?如何在此示例中实例化Foo?
答案 0 :(得分:0)
创建的类<em> “知道”它的定义ClassLoader
,JVM将使用定义的类加载器解析它的引用。但是,正如您从堆栈跟踪中看到的那样,clojure.lang.RT.load
尝试以不兼容的方式解析资源。通过查看其代码,可以归结为following method:
static public ClassLoader baseLoader(){
if(Compiler.LOADER.isBound())
return (ClassLoader) Compiler.LOADER.deref();
else if(booleanCast(USE_CONTEXT_CLASSLOADER.deref()))
return Thread.currentThread().getContextClassLoader();
return Compiler.class.getClassLoader();
}
通过此代码,您可以获得问题的解决方案:
Compiler.LOADER
的值设置为自定义类加载器。Compiler.LOADER
仍未绑定且RT.USE_CONTEXT_CLASSLOADER
评估为true
,则可以将线程的context loader设置为自定义类加载器。Compiler.class.getClassLoader()
将返回您的自定义类加载器。