2016-07-29 8 views
4
  • 私は、クラスAは、私はCustomClassLoaderがdefineClass(className, byte[], offset, length)を使用するために、ClassLoaderを拡張作成したB.
  • を拡張しています。
  • 私はnew CustomClassLoader(Thread.currentThread().getContextClassLoader())をインスタンス化しました。 したがって、私のCustomClassLoaderの親は、現在のスレッドのClassLoaderです。
  • ASMフレームワークを使用してBクラスを変更しました。私は変更されたクラスを.classファイルに書き出し、逆コンパイラを使って動作させるようにしています。そして、それは動作します。
  • 私はCustomClassLoaderに変更されたBクラスを追加しました
  • 私はCustomClassLoaderでThread.currentThread().setContextClassLoader()を設定しました。
  • Class.forName(String, true, the CustomClassLoader)を使用してAをロードしました。
  • しかし、ロードされたBクラスは元のクラスであるようです。

何が間違っていましたか? 詳細情報が必要な場合は、詳細なトピックはGitHubです。修正されたスーパークラスをJavaでロードするには?

答えて

2

Javaクラスローダー最初子供を見る前に親クラスローダーを検索してください。

クラスローダにloadClassメソッドクラスをロードするために呼び出されたときに、順番に、 をこれらのタスクを実行します。クラスがすでにロードされている場合は

  1. 、それはそれを返します。
  2. それ以外の場合は、新しいクラスの検索を親クラスローダに委譲します。
  3. 親クラスローダーがクラスを見つけられない場合、loadClassはfindClassメソッドを呼び出して、クラスを検索してロードします。

Understanding Extension Class Loading - オラクル)

あなたはその順番を変更したい場合は、あなたにもloadClassメソッドをオーバーライドする必要がありますが、そこに多くの注意点があり、あなたは非常によくクラスローディングを理解していない限り、それはお勧めしません。

  • 簡単なオプションは、親クラスローダーが元のクラスBを見つけられないようにすることです。
+0

"A"クラスがロードされていないので、ClassLoaderの子はClassLoaderの親にクラスのロードを委譲します。 しかし、Bは子にロードされます(変更されたバージョンは子にロードされる)ので、AがBを拡張するためにAがBを必要とする場合、Bが親からロードされる理由 –

+0

「しかし、Bは子供の中に入っている」とはどういう意味ですか? Bが親クラスローダーに存在する場合、それは子にロードされません。なぜなら、 'loadClass'をオーバーライドしないすべてのクラスローダーは最初にその親に委譲し、子クラスノードで見つからない場合にのみロードしようとします親 –

+0

実行時にBクラスのバイトコードを変更する必要があります。 変更されたBクラスを保存するには、parent.defineClass()が表示されず、元のBクラスが親クラスローダーに存在する可能性があるため、child.defineClass()を使用する必要があります。 - Bが子 に変更し、ロードされた - Aが子からロードされる - >親 への委譲 - B親 からロードしているように見える - - AはB が延びBが親に保存されていないので、親ロードBはURLを使用して私は思う - 元の元のBのクラスをロード - Bは2回読み込まれます:元の親と子で修正。 –

1

は、いくつかのことを知ってあります。それは影響を与えないよう、スレッドのコンテキストクラスローダを扱うほとんどのものについては、

  • は、廃止されました。それはもっと慣習に似ています。他のコードがクエリを使用している場合は、それを設定すると影響があります。標準のクラスローディングプロセスの場合、意味はありません。ドキュメンテーションにそれが言及されておらず、それが関連するもののように見えることは残念です。おそらく、それが追加されたときにもっと意味を持つことを意図していました。
  • pointed out by Erwin Bolwidtとして、カスタムローダーを使用してAをロードすると、親ローダに委譲され、親によってロードされたクラスAが返されます。
  • の場合、のクラス参照を解決する場合、JVMは常にリファラーのローダーを定義するを使用します。 BからAからの参照が解決されたときに、JVMは常にA

最後の点が暗示するクラスを定義し、親ローダを使用することは、最初に、独自のクラスを探すために、カスタムクラスローダを変更しても、最初に親を照会する標準モデルに従うのではなく、それ自身がAを持たない場合は問題を解決しません。それでも、親を使用して参照が解決される親のAを返します。あなたがAを求める前に、defineClassを呼び出しているので、カスタムローダーは、すでにそれは誰もが今までB ...

のためにそれを求めたのであれば、あなたのカスタムを聞かせでき返したことBを定義しているように、検索順序は、全く関係ありません。ローダーもロードしてAと定義します。または、Bがロードされる前に、ClassLoaderのシステム上のdefineClassへのアクセスオーバーライドを伴うReflectionを使用します。一番きれいな解決策は、Javaエージェントとしてクラス変更ロジックを実装して、Instrumentation APIを使用して読み込み時にBの定義を傍受して変更できるようにすることです。

関連する問題