Clojure中的Class / forName不尊重ContextClassLoader?

时间:2012-06-07 23:40:19

标签: clojure classloader

我已经回复了正在运行的服务,并且有一个var指向一个加载了插件的类加载器(安装了my.package)。

REPL使用的DynamicClassLoader不包含我希望与之交互的插件;我希望能够使用从插件加载的类,尽管有这个限制。

以下作品:

=> (.loadClass plugin-classloader "my.package.MyClass")
my.package.MyClass

...而以下内容没有(明确覆盖线程上下文类加载器):

=> (do
     (.setContextClassLoader (Thread/currentThread) plugin-classloader)
     (Class/forName "my.package.MyClass"))
ClassNotFoundException my.package.MyClass  java.net.URLClassLoader$1.run (URLClassLoader.java:202)

...这两者都没有(明确覆盖线程上下文类加载器 clojure.lang.Compiler / LOADER引用):

=> (let [dcl (clojure.lang.DynamicClassLoader. plugin-classloader)]
     (.setContextClassLoader (Thread/currentThread) dcl)
     (with-bindings* {clojure.lang.Compiler/LOADER dcl}
       (eval '(pr-str (Class/forName "my.package.MyClass")))))
ClassNotFoundException my.package.MyClass  java.net.URLClassLoader$1.run (URLClassLoader.java:202)

......而且这两者都没有:

=> my.package.MyClass
CompilerException java.lang.ClassNotFoundException: my.package.MyClass, compiling:(NO_SOURCE_PATH:0)

设置时Class.forName()不应该使用线程上下文类加载器吗?我正在尝试对第三方代码进行内省魔术调用;即使应该设置线程上下文类加载器,有问题的工具也会因ClassNotFoundExceptions而失败。


在我明确设置上下文类加载器的情况下,堆栈跟踪演示了Clojure的DynamicClassLoader(而不是plugin-classloader var中的BundleClassLoader)正在使用中:

=> (e)
java.lang.ClassNotFoundException: my.package.MyClass
 at java.net.URLClassLoader$1.run (URLClassLoader.java:202)
    java.security.AccessController.doPrivileged (AccessController.java:-2)
    java.net.URLClassLoader.findClass (URLClassLoader.java:190)
    clojure.lang.DynamicClassLoader.findClass (DynamicClassLoader.java:61)
    java.lang.ClassLoader.loadClass (ClassLoader.java:306)
    java.lang.ClassLoader.loadClass (ClassLoader.java:247)
    java.lang.Class.forName0 (Class.java:-2)
    java.lang.Class.forName (Class.java:169)

1 个答案:

答案 0 :(得分:5)

由REPL调用的

clojure.lang.Compiler/eval使用clojure.lang.Compiler/LOADER,而不是线程本地类加载器。在调用eval之前,需要将适当的类加载器绑定到此var - 因此添加一个包装层可解决此问题:

=> (let [dcl (clojure.lang.DynamicClassLoader. plugin-classloader)]
     (with-bindings {clojure.lang.Compiler/LOADER dcl}
       (eval '(Class/forName "my.package.MyClass"))))
my.package.MyClass