6

実行中のサービスに REPL されており、プラグインがロードされた (インストール済みの) クラスローダーを指す 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 (プラグイン クラスローダー変数の 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)
4

1 に答える 1

6

clojure.lang.Compiler/evalREPL によって呼び出される はclojure.lang.Compiler/LOADER、スレッドローカル クラスローダーではなく を使用します。が呼び出される前に、適切なクラスローダーがこの var にバインドされる必要があります。evalそのため、ラッピングのレイヤーを追加することで、この問題を回避できます。

=> (let [dcl (clojure.lang.DynamicClassLoader. plugin-classloader)]
     (with-bindings {clojure.lang.Compiler/LOADER dcl}
       (eval '(Class/forName "my.package.MyClass"))))
my.package.MyClass
于 2012-06-08T19:45:50.083 に答える