Javaassistだけでなく、他のバイトコード エンジニアリング ライブラリでも実行できます。その魔法はJava Attach APIにあります。これにより、プログラムを実行中の JVM にアタッチ (およびロードされたクラスを変更) できます。
これはcom.sun.tools.attach
パッケージに含まれており、その名前が示すように、Oracle JVM に固有のものです。それにもかかわらず、JDK ツールは「実行中の JVM に接続する」機能をサポートするためにそれを好みjstack
、使用するため、ここにとどまると言っても過言ではありません。jmap
Attach API に関するドキュメントはかなり説明的であり、このOracle ブログ投稿では、実行時にエージェントをアタッチする方法を示しています。一般に、それは次のように要約されます。
- et alを使用して、再変換プログラムを「通常の」
-javaagent
方法で作成しますpremain
premain
に名前を変更agentmain
Agent-Class
エージェント クラスを含み、エージェント ( - をagentmain
含む) クラスを指すマニフェストを持つ一時 JAR ファイルを作成し、次のようにCan-Retransform-Classes
設定します。true
- ターゲット JVM (潜在的に同じプロセス) の PID を取得し、それに一時的な jar をアタッチします。
ありがたいことに、API はユーザー側で多くの作業を行わなくてもこれを行うことができますが、実行時に JAR 生成を行う場合、エージェントに必要なすべてのクラスをパッケージ化するのは少し難しいかもしれません。
実行時にプロファイラーをアタッチするデモ エージェントを含めたいと思っていましたが、長すぎて投稿できませんでした。それにもかかわらず、私はそれをGithub repoに入れました。
このアプローチの注意点tools.jar
は、プログラムが JDK に同梱され、JRE には存在しない に依存するようになることです。tools.jar
これは、アプリケーションに同梱 (またはアプリケーションに抽出) することで回避できますがattach
、Attach API が必要とするネイティブ ライブラリをアプリケーションに提供する必要があります。上記のリンク先のリポジトリにあるすべてのプラットフォーム用のライブラリを含めましたが、自分で入手することもできます。
ユースケースによっては、これが理想的な場合とそうでない場合があります。しかし、それは確かに機能します!
これは質問では明確ではありませんが、実行時に自分のクラスと完全に「ホットスワップ」したい場合は、バイトコード操作ライブラリを使用する必要はありません。代わりに、クラスを個別にコンパイルして (パッケージ、クラス名などを同じにするtransform
) 、ターゲット クラスで が呼び出されたときに新しいクラスのバイトを返すだけです。