2012-06-07 27 views
5

我被複制到一個正在運行的服務中,並且有一個var指向一個加載插件的類加載器(安裝了my.package)。Clojure中的class/forName不尊重ContextClassLoader?

REPL使用的DynamicClassLoader不包含我希望與之交互的插件;我希望能夠使用插件加載的類,儘管有這種限制。

以下工作:

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

...而以下不(明確重寫線程上下文的classloader):

=> (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()使用線程上下文的classloader設置是什麼時候?我正在嘗試將一些調用轉化爲執行內省魔法的第三方代碼;即使在設置線程上下文類加載器時,所討論的工具也會因爲ClassNotFoundException而失敗。


的情況下,我明確設置的上下文ClassLoader,堆棧跟蹤表明,Clojure的DynamicClassLoader中(而不是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) 
+0

好像'eval'是玩一些把戲那裏......你可以嘗試同樣的事情在編譯clojure代碼? – Ankur

+0

@Ankur - 你的意思是AOT編譯的?我的理解是,Clojure的實現是這樣的,它是*所有*編譯代碼,甚至在REPL中輸入。 –

+0

@Ankur事實證明,你是對的 - 它是編譯好的代碼,但當'clojure.lang.Compiler/eval'被調用時,綁定到'clojure.lang.Compiler/LOADER'的'DynamicClassLoader'實例。 –

回答

5

由REPL調用的clojure.lang.Compiler/eval使用clojure.lang.Compiler/LOADER,而不是線程本地類加載器。適當的類加載器需要綁定到eval在此之前變種被稱爲 - 所以添加解決此問題,包裝工程一層:

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