JDTコンパイラでクラスをコンパイルするときに、Playはどのクラスローダを使用しますか?

実行時にjarファイルをPlayクラスパスに追加するPlayプラグインを作成しようとしています。 onLoad が呼び出されると、JDTコンパイラがそれらを使用してアプリケーションクラスの依存関係を解決できるように、一連のJARをロードする必要があります。これらのjarファイルは、標準の lib/ディレクトリにはないため、Playの開始時にシステムクラスパスにロードされません。

実際にjarファイルをロードすることは問題ではありません。必要な各jarファイルをURLとして指定し、それらを URLClassLoader のインスタンスに渡します。

多くの研究の後、Playが使用するクラスローダーは Play.classloader にあり、私の最初の計画は Play.ApplicationClassloader を拡張する独自のクラスローダーを作成することでした>。このクラスローダは、 Play.ApplicationClassloader の標準機能に委譲する前に、URLClassLoaderのインスタンスを使用してクラスを検索します。私はその後、Playクラスローダーを新しいインスタンスに置き換えようとしていました。

Play.classloader = new MyExtensionClassLoader();

私が打つ問題は、JDTコンパイラが Play.classloader インスタンスを使用してクラスをロードしているように見えないことです。

だから私は2つの質問があります:

JDTコンパイラは、 Play.classloader インスタンスを使用していない場合、実際にどのクラスパスを使用していますか?

より一般的には、JDTコンパイラで使用できるように、実行時にjarファイルをPlayに読み込む方法はありますか?

1

2 答え

それはうまくいくとは思わない。

Playには独自のクラスローダーがあり、クラスが "マネージドプレイアプリケーションクラス"(JDTコンパイラランタイムでコンパイルされたクラス)であるかどうかを最初に確認し、デフォルトのjvm-oneである親クラスローダーにフォールバックします。

したがって、すべてのplayframework-coreクラスとHibernateクラスのような他のライブラリは、すべてデフォルトのjvm-classloaderから通常のクラスとしてロードされます。

私はあなたが私を理解してほしい:)

モルテン

1
追加された
それは意味をなさない。前述のとおり、 Play.classloader にある ApplicationClassloader のインスタンスを自分のインスタンスに置き換えました。私はそれがアプリケーションクラスのために呼び出されることを知っているが、それはJDTコンパイラは、そのクラスローダーを使用していないようだ。
追加された 著者 Matt Biggin,
私は、 Application.compiler.compile()... findType()がクラスをロードするために新しいインスタンスを使用する Play.classloader を置き換えると仮定しました。しかし、これは事実ではありません。私はこのセクションの findType()にフックすることを望んでいました: '//これは標準クラスのバイトです[] bytes = Play.classloader.getClassDefinition(name);'これは ApplicationCompiler の184-185行目にあります。
追加された 著者 Matt Biggin,
もう少し調査した後、魔法はApplicationCompilerの 'private NameEnvironmentAnswer findType(final String name)'で発生します.InterruptがgetResourceAsStream(name)を使うPlay.classloader.getClassDefinition(name)を介してクラスのバイトをロードしますクラスローダーメソッド)。
追加された 著者 mbknor,
コメント欄が小さすぎるため、新しい回答を作成します。
追加された 著者 mbknor,

あなたの問題は、ApplicationClassloaderの親クラスローダーであるjava.lang.Classloaderを変更できないということです。

コンストラクタを見ると、ApplicationClassloader.classがロードされたクラスローダーが常に選択されることがわかります。

ApplicationClassloaderのコンストラクタに親クラスローダをparamとして送ることができれば、これを行うことができます:

新しいClassloaderAは、親クラスローダーを持つjava.lang.ClassloaderをJVM-defaultとして拡張します。次に、ClassloaderAで、findClassとgetResourceAsStreamをオーバーライドして、親を探す前にjarファイルを探します。 Play.classloaderに親クラスローダとしてClassloaderAのインスタンスを持つApplicationClassloaderの新しいインスタンスを与えることができます。

私は、これがClassloader-Hirarchyを正しいものにすると思います。

0
追加された
私はそれを与えるだろう。ありがとう。
追加された 著者 Matt Biggin,
いくつかの質問。 1/JVM-defaultクラスローダーを取得するにはどうすればよいですか? ClassloaderA が親であるように、 ApplicationClassloader の新しいインスタンスを作成するにはどうすればいいですか( Thread.currentThread()。getContextClassLoader()?)クラスローダー?
追加された 著者 Matt Biggin,
JVMのデフォルトのクラスローダーを取得するにはどうすればいいですか?それはシステムプロパティ "java.system.class.loader"で定義することができます。起動時に-D java.system.class.loader = MyCustomClassLoaderを指定することができます
追加された 著者 Matt Biggin,
私が 'default classloader'と言うとき、私はtrixingを開始する前に、最初のクラス(またはすべてのクラス)をロードしている最初のクラスローダーを意味します。すべてのclassobjectsは、ロードされたクラスローダーインスタンスへの参照を持つので、Integer.class.getClassloader()は、私が話しているクラスローダーインスタンスを返します
追加された 著者 mbknor,