web-dev-qa-db-ja.com

どのクラスがどのJARからロードされるかを調べる方法は?

実行時にどのクラスがどのjarからロードされるかを決定する方法はありますか?

私たちは皆、JARの地獄に行ったことがあると思います。この問題に何度も遭遇し、プロジェクトのClassNotFoundExceptionsとNoClassDefFoundErrorsのトラブルシューティングを行いました。 jar内のクラスのすべてのインスタンスを見つけたり、コードで消去法を使用してCNFEが原因を見つけたりすることは避けたいと思います。

プロファイリングまたは管理ツールは、この種の情報を提供しますか?

この問題は、クラスがロードされるときにこの情報が必要なため、非常に厄介です。そこにたどり着く、または記録して見つける方法が必要ですが、これを行う方法は何も知りませんよね?

OSGiとバージョン管理されたバンドル/モジュールがこれを問題のないものにすることを目指していることは知っています...しかし、すぐになくなることはないようです。 :)

注:これは 質問 がバージョン管理されたjarからロードされたクラスに関連する私の質問のサブセットであることがわかりました。

Update:やや関連性がありますが、この投稿では、jar内(現在のディレクトリの下)またはM2_REPO内でクラスを検索する戦略について説明しています。 JarScan、特定のクラスのすべてのサブフォルダー内のすべてのJARファイルをスキャンします

アップデート2:これも多少関連しています JBoss Tattletale

30
cwash

-verbose:classスイッチをJavaコマンドに渡すと、ロードされた各クラスとそのロード元が出力されます。

Joops は、不足しているクラスを事前に見つけるための優れたツールでもあります。

56
Jason Day

コードから呼び出すことができます:

myObject.getClass().getProtectionDomain().getCodeSource()

(注:getProtectionDomainは残念ながらnull(悪いデザイン)を返す可能性があるため、「適切なコード」がそれをチェックします。)

14

上記のJasonDayが言及したJVMフラグ用のMBeanがあります。

JBossを使用している場合、ネイティブJMX MBeanサーバーを構成に追加すると、JMXを使用してオンデマンドでこれをいじることができます。次の-Dを追加します。

-Dcom.Sun.management.jmxremote.port=3333
-Dcom.Sun.management.jmxremote.authenticate=false
-Dcom.Sun.management.jmxremote.ssl=false
-Djboss.platform.mbeanserver 
-Djavax.management.builder.initial=org.jboss.system.server.jmx.MBeanServerBuilderImpl
-DJBOSS_CLASSPATH="../lib/jboss-system-jmx.jar"

そして、Java.lang:Classloading MBeanでこの設定を確認し、その場でオン/オフを切り替えることができます。これは、特定のコードの実行中にのみオンにしたい場合に役立ちます。

完全修飾クラス名を入力してクラス階層のどこからロードされたかを確認できるMBeanもあります。 MBeanはLoaderRepositoryと呼ばれ、displayClassInfo()オペレーションを呼び出してFQCNを渡します。

4
cwash

WebSphere(WAS)では、「クラスローダービューアー」と呼ばれる機能を使用できます。

最初に、[サーバー]> [サーバーの種類]> [WebSphereアプリケーションサーバー]> [server_name]> [クラスローダービューアーサービス]をクリックしてクラスローダービューアーを有効にし、サービスを有効にしてサーバーを再起動します。

次に、[トラブルシューティング]> [クラスローダービューア]に移動して、クラス名またはパッケージ名を検索できます。

https://www-01.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.nd.doc/ae/ttrb_classload_viewer.html?lang=en

0
cwash

JMX操作を簡単にエクスポートして、次のようにプロセス内のロードされたクラスのパッケージ情報にアクセスできます。

  public static final class Jmx {

    @JmxExport
    public static Reflections.PackageInfo getPackageInfo(@JmxExport("className") final String className) {
      return Reflections.getPackageInfo(className);
    }
  }

これは、エクスポートして呼び出すための簡単な単体テストです。

  @Test
  public void testClassLocator() throws IOException, InstanceNotFoundException, MBeanException, ReflectionException {
    Registry.export(Jmx.class);
    Reflections.PackageInfo info = (Reflections.PackageInfo) Client.callOperation(
            "service:jmx:rmi:///jndi/rmi://:9999/jmxrmi",
            Jmx.class.getPackage().getName(),
            Jmx.class.getSimpleName(), "getPackageInfo", Registry.class.getName());
    System.out.println(info);
    Assert.assertNotNull(info);
  }

これはすべて、spf4jのいくつかの小さなユーティリティライブラリを使用して基づいています( http://www.spf4j.org

あなたはこのコードを見ることができます at そしてテスト at

0
user2179737