パッケージ java.lang.instrument
ノート: 開発者/管理者は、他のJARファイルからバイトコードを任意に変換できるため、デプロイするJavaエージェントのコンテンツおよび構造の信頼性の検証を担当します。 これは、バイトコードを含むJarが信頼できるものとして検証された後に発生するため、Javaエージェントの信頼性によって、プログラム全体に対する信頼性を判断できます。
エージェントはJARファイルとして配備されます。 JARファイルに含まれるマニフェストの属性は、エージェントを起動するためにロードされるエージェント・クラスを指定します。 エージェントはいくつかの方法で起動できます。
コマンドライン・インタフェースをサポートする実装の場合、コマンドラインでオプションを指定してエージェントを起動できます。
実装では、VMの起動後にエージェントを起動するメカニズムがサポートされる場合があります。 たとえば、実行中のアプリケーションにツールを接続して、ツールのエージェントをそのアプリケーションにロードし始められるようなメカニズムを提供できる実装もあります。
エージェントは、実行可能JARファイル内のアプリケーションにパッケージ化できます。
次に、エージェントを起動するこれらの各方法について説明します。
コマンドライン・インタフェースからのエージェントの起動
実装によってコマンドライン・インタフェースからエージェントを起動する手段が提供される場合、コマンドラインに次のオプションを追加してエージェントを起動します。
-javaagent:<jarpath>[=<options>]
ここで、<jarpath>はエージェントJARファイルへのパス、<options>はエージェント・オプションです。
エージェントJARファイルのマニフェストには、メイン・マニフェストに属性 Premain-Classが含まれている必要があります。 この属性の値は、エージェント・クラスの名前です。 エージェント・クラスは、基本的にmainアプリケーション・エントリ・ポイントと同様のpublic static premainメソッドを実装する必要があります。 Java Virtual Machine (JVM)が初期化されると、premainメソッドがコールされ、その後、実際のアプリケーションのmainメソッドがコールされます。 起動を続行するには、premainメソッドが戻される必要があります。
premainメソッドには2つのシグネチャのうちのいずれかがあります。 JVMはエージェント・クラスで最初に次のメソッドを呼び出そうとします。
public static void premain(String agentArgs, Instrumentation inst)
エージェント・クラスにこのメソッドが実装されていない場合は、次のメソッドを呼び出そうとします。
public static void premain(String agentArgs)
また、エージェント・クラスには、VMの起動後にエージェントを起動するときに使用するagentmainメソッドがあります(次を参照)。 コマンド行オプションを使用してエージェントを開始した場合は、agentmainメソッドが呼び出されません。
各エージェントは、agentArgsパラメータ経由でエージェント・オプションが渡されます。 エージェント・オプションは単一の文字列として渡され、追加の解析はエージェント自身によって行われます。
エージェントを起動できない場合(たとえば、エージェント・クラスをロードできない、またはエージェント・クラスに適切なpremainメソッドがないなど)、JVMは中断します。 premainメソッドが、キャッチされない例外をスローすると、JVMが異常終了します。
実装がコマンド行インタフェースからエージェントを開始する方法を提供する必要はありません。 その場合、前述のように-javaagentオプションがサポートされます。 -javaagentオプションは、同じコマンド行で複数回使用できるため、複数のエージェントを起動できます。 premainメソッドは、エージェントがコマンドラインで指定される順序でコールされます。 複数のエージェントで同じ<jarpath>を使用できます。
エージェントpremainメソッドの実行内容に関するモデリング制約はありません。 作成側スレッドを含め、アプリケーションmainが実行できることは、すべてpremainで有効です。
VM起動後のエージェントの起動
実装によっては、VMの開始後にエージェントを開始するメカニズムが用意されている場合もあります。 開始する方法の詳細は、実装によって異なりますが、通常はアプリケーションが開始済みで、そのアプリケーションmainメソッドが呼出し済みです。 VMの開始後にエージェントを開始できる場合は、次の条件が適用されます。
エージェントJARのマニフェストには、メインのmanfiestに属性
Agent-Classが含まれている必要があります。 この属性の値は、エージェント・クラスの名前です。エージェント・クラスはpublic static
agentmainメソッドを実装する必要がある。
agentmainメソッドには、可能な2つのシグネチャのいずれかがあります。 JVMはエージェント・クラスで最初に次のメソッドを呼び出そうとします。
public static void agentmain(String agentArgs, Instrumentation inst)
エージェント・クラスにこのメソッドが実装されていない場合は、次のメソッドを呼び出そうとします。
public static void agentmain(String agentArgs)
エージェント・クラスは、コマンドライン・オプションを使用してエージェントを起動するときに使用するpremainメソッドを持つこともできます。 VMの開始後にエージェントが開始されると、premainメソッドは呼び出されません。
エージェントは、agentArgsパラメータ経由でエージェント・オプションが渡されます。 エージェント・オプションは単一の文字列として渡され、追加の解析はエージェント自身によって行われます。
agentmainメソッドでは、エージェントの開始に必要な必須の初期化を実行するようにしてください。 開始が完了すると、メソッドを返すようにします。 エージェントを開始できない場合(たとえばエージェント・クラスをロードできなかったため、またはエージェント・クラスに適切なagentmainメソッドがないため)、JVMは異常終了します。 agentmainメソッドが捕捉されない例外をスローした場合、その例外は無視されます(ただし、トラブルシューティングのためにJVMによってログに記録される場合があります)。
実行可能なJARファイルへのエージェントの組込み
JARファイル仕様では、実行可能JARファイルとしてパッケージ化されるスタンドアロン・アプリケーションのマニフェスト属性を定義します。 実装で、実行可能JARとしてアプリケーションを起動するメカニズムがサポートされている場合、メイン・マニフェストにLauncher-Agent-Class属性が含まれ、アプリケーションのmainメソッドが起動される前に開始するエージェントのクラス名を指定できます。 Java仮想マシンは、エージェント・クラスで次のメソッドを呼び出そうとします。
public static void agentmain(String agentArgs, Instrumentation inst)
エージェント・クラスにこのメソッドが実装されていない場合は、次のメソッドを呼び出そうとします。
public static void agentmain(String agentArgs)
agentArgsパラメータの値は、常に空の文字列です。
agentmainメソッドは、エージェントを起動して戻すために必要な初期化を行う必要があります。 エージェントを起動できない場合、たとえば、エージェント・クラスをロードできない場合、エージェント・クラスが準拠するagentmainメソッドを定義していない場合、またはagentmainメソッドが捕捉されない例外またはエラーをスローした場合、JVMは異常終了します。
エージェント・クラスおよびエージェント・クラスで使用可能なモジュール/クラスのロード
エージェントJARファイルからロードされたクラスは、システム・クラス・ローダーによってロードされ、システム・クラス・ローダーの名前なしモジュールのメンバーです。 通常、システム・クラス・ローダーは、アプリケーションのmainメソッドを含むクラスも定義します。
エージェント・クラスに表示されるクラスは、システム・クラス・ローダーから参照できるクラスであり、最小限には次のクラスが含まれます。
ブート・レイヤーのモジュールによってエクスポートされるパッケージ内のクラス。 ブート・レイヤーにすべてのプラットフォーム・モジュールが含まれているかどうかは、初期モジュールまたはアプリケーションの起動方法によって異なります。
システム・クラス・ローダーによって定義できるクラス(通常はクラス・パス)は、名前のないモジュールのメンバーになります。
ブートストラップ・クラス・ローダーによって定義されるようにエージェントが配置するクラスが、名前のないモジュールのメンバーになります。
エージェント・クラスが、ブート・レイヤーにないプラットフォーム(または他の)モジュール内のクラスにリンクする必要がある場合、これらのモジュールがブート・レイヤーにあることを確認する方法でアプリケーションを起動する必要がある場合があります。 たとえば、JDK実装では、--add-modulesコマンドライン・オプションを使用して、起動時に解決するルート・モジュールのセットにモジュールを追加できます。
エージェントがブートストラップ・クラス・ローダーによってロードされるように配置するサポート・クラス(後述のappendToBootstrapClassLoaderSearchまたはBoot-Class-Path属性を使用)は、ブートストラップ・クラス・ローダーに定義されたクラスにのみリンクする必要があります。 すべてのプラットフォーム・クラスをブート・クラス・ローダーで定義できるという保証はありません。
カスタム・システム・クラス・ローダーが(getSystemClassLoaderメソッドで指定されているシステム・プロパティjava.system.class.loaderを使用して)構成されている場合は、appendToSystemClassLoaderSearchで指定されているとおりにappendToClassPathForInstrumentationメソッドを定義する必要があります。 つまり、カスタム・システム・クラス・ローダーは、システム・クラス・ローダー検索にエージェントJARファイルを追加するメカニズムをサポートしている必要があります。
マニフェスト属性
エージェントJARファイルには次のマニフェスト属性が定義されています。
Premain-Class- JVMの起動時にエージェントが指定される場合は、この属性でエージェント・クラスを指定します。 つまり、
premainメソッドが含まれるクラスです。 JVMの起動時にエージェントが指定される場合は、この属性が必須です。 この属性が存在しない場合、JVMは異常終了します。 ノート: これはクラス名であり、ファイル名やパスではありません。Agent-Class- VMの開始後にエージェントを開始するメカニズムが実装でサポートされている場合は、この属性でエージェント・クラスを指定します。 つまり、
agentmainメソッドが含まれるクラスです。 エージェントが起動されない場合は、この属性が必要です。 ノート: これはクラス名であり、ファイル名やパスではありません。Launcher-Agent-Class- アプリケーションを実行可能なJARとして起動するメカニズムが実装でサポートされている場合、アプリケーションの
mainメソッドが起動される前に起動するエージェントのクラス名を指定するために、メイン・マニフェストにこの属性が含まれることがあります。Boot-Class-Path- ブートストラップ・クラス・ローダーで検索されるパスのリストです。 パスはディレクトリまたはライブラリを表します。多くのプラットフォームでは、通常、JARファイルまたはzipライブラリとして参照されます。 クラスを検索するプラットフォーム固有のメカニズムが失敗すると、これらのパスがブートストラップ・クラス・ローダーで検索されます。 パスはリストの順序で検索されます。 リスト内のパスは1つ以上の空白文字で区切られます。 パスの構文は、階層型URIのパス・コンポーネントの構文になります。 スラッシュ文字(/)で始まると絶対パス、それ以外の場合は相対パスです。 相対パスはエージェントのJARファイルの絶対パスに対して解決されます。 パスが不正または存在しない場合は無視されます。 VMの開始後にエージェントが開始される場合は、JARファイルを表さないパスは無視されます。 この属性はオプションです。
Can-Redefine-Classes- ブール値(
trueまたはfalse、大文字小文字は区別しない)。 クラスを再定義する機能がこのエージェントに必要かを表します。true以外の値はfalseであるとみなされます。 この属性はオプションで、デフォルトはfalseです。Can-Retransform-Classes- ブール値(
trueまたはfalse、大文字小文字は区別しない)。 クラスを再変換する機能がこのエージェントに必要かを表します。true以外の値はfalseであるとみなされます。 この属性はオプションで、デフォルトはfalseです。Can-Set-Native-Method-Prefix- ブール値(
trueまたはfalse、大文字小文字は区別しない)。 ネイティブ・メソッドの接頭辞を設定する機能がこのエージェントに必要かを表します。true以外の値はfalseであるとみなされます。 この属性はオプションで、デフォルトはfalseです。
エージェントJARファイルでは、マニフェスト内にPremain-Class属性と Agent-Class属性の両方が存在することがあります。 -javaagentオプションを使用したコマンド行でエージェントを開始する場合は、 Premain-Class属性でエージェント・クラスの名前を指定し、 Agent-Class属性は無視されます。 同様に、VMの開始後にエージェントが開始される場合は、Agent-Class属性でエージェント・クラスの名前を指定し、Premain-Class属性は無視されます。
モジュール内のコードの計測
ブートストラップ・クラス・ローダーの検索パスまたはメイン・エージェント・クラスをロードするクラス・ローダーの検索パスにサポート・クラスをデプロイするエージェントを支援するために、Java仮想マシンでは、変換されたクラスのモジュールが配置され、両方のクラス・ローダーの名前のないモジュールが読み取られます。
- 導入されたバージョン:
- 1.5
-
インタフェースのサマリー インタフェース 説明 ClassFileTransformer クラス・ファイルのトランスフォーマ。Instrumentation このクラスは、Javaプログラミング言語コードを計測するためのサービスを提供します。 -
クラスのサマリー クラス 説明 ClassDefinition このクラスは、Instrumentation.redefineClassesメソッドに対するパラメータ・ブロックとして機能します。 -
例外のサマリー 例外 説明 IllegalClassFormatException 入力パラメータが無効な場合にClassFileTransformer.transformの実装によってスローされます。UnmodifiableClassException 指定されたクラスの1つを変更できない場合、Instrumentation.redefineClassesの実装によってスローされます。UnmodifiableModuleException モジュールを変更できないことを示すためにスローされます。