Javaのヒント105:JWhichを使用してクラスパスをマスターする

開発者は、Javaクラスパスを処理するときにフラストレーションを感じることがあります。特にアプリケーションのクラスパスがディレクトリやファイルでいっぱいになった場合、クラスローダーがどのクラスをロードするかは必ずしも明確ではありません。この記事では、ロードされたクラスファイルの絶対パス名を表示できるツールを紹介します。

クラスパスの基本

Java仮想マシン(JVM)は、クラスローダーを使用して、アプリケーションが使用するクラスを必要に応じてロードします。CLASSPATH環境変数はどこサードパーティ製およびユーザ定義クラスを検索するクラスローダを伝えます。また-classpathCLASSPATH環境変数で指定されたクラスパスをオーバーライドするJVMコマンドライン引数を使用して、アプリケーションごとにクラスパスを指定することもできます。

クラスパスエントリは、パッケージに含まれていないクラスのクラスファイルを含むディレクトリ、パッケージ内のクラスのパッケージルートディレクトリ、またはクラスを含むアーカイブファイル(.zipファイルや.jarファイルなど)にすることができます。クラスパスエントリは、Unixタイプのシステムではコロンで区切られ、MSWindowsシステムではセミコロンで区切られます。

クラスローダーは委任階層で編成され、各クラスローダーには親クラスローダーがあります。クラスローダーがクラスを見つけるように要求されると、クラス自体を見つけようとする前に、まずその要求を親クラスローダーに委任します。システムにインストールされたJDKまたはJREによって提供されるデフォルトのクラスローダーであるシステムクラスローダーは、CLASSPATH環境変数または-classpathJVMコマンドライン引数を使用してサードパーティおよびユーザー定義のクラスをロードします。システムクラスローダーは、拡張クラスに委任して、Java拡張メカニズムを使用するクラスをロードします。拡張クラスローダーは、ブートストラップクラスローダーに委任して(ここでお金が止まります!)、コアJDKクラスをロードします。

特殊なクラスローダーを開発して、JVMがクラスを動的にロードする方法をカスタマイズできます。たとえば、ほとんどのサーブレットエンジンは、カスタムクラスローダーを使用して、カスタムクラスパスで指定されたディレクトリで変更されたサーブレットクラスを動的に再読み込みします。

特に重要であり、非常に驚​​かされるのは、クラスローダーがクラスパスに表示される順序でクラスをロードすることです。最初のクラスパスエントリから開始して、クラスローダーは指定された各ディレクトリまたはアーカイブファイルにアクセスし、ロードするクラスを見つけようとします。適切な名前で最初に見つかったクラスがロードされ、残りのクラスパスエントリはすべて無視されます。

シンプルに聞こえますよね?

クラスパスのトリック

彼らがそれを認めるかどうかにかかわらず、初心者とベテランのJava開発者は、ある時点で(通常は最悪の瞬間に!)厄介なクラスパスにだまされてきました。アプリケーションの依存するサードパーティクラスとユーザー定義クラスの数が増え、クラスパスが考えられるすべてのディレクトリとアーカイブファイルのダンプグラウンドになるため、クラスローダーが最初にロードするクラスが常に明確になるとは限りません。これは、クラスパスに重複するクラスエントリが含まれているという不幸なイベントで特に当てはまります。クラスローダーは、クラスパスで見つかった最初の適切な名前のクラスをロードし、優先度の低い他のすべての適切な名前のクラスを効果的に「非表示」にすることを忘れないでください。

このクラスパスのトリックの犠牲になるのは簡単です。ホットキーボードで長い一日を過ごした後、クラスの別のバージョンがのディレクトリにあることに気づかずに、クラスの最新かつ最大のバージョンをアプリケーションにロードしようとして、クラスパスにディレクトリを追加します。クラスパスの優先順位が高くなります。ガッチャ!

JWhich:シンプルなクラスパスツール

フラットパス宣言に固有の優先順位の問題は、Javaクラスパスに固有のものではありません。問題の解決策を見つけるには、伝説的なソフトウェアの巨人の肩に立つだけで済みます。 Unixオペレーティングシステムのwhichコマンドは名前を取り、その名前がコマンドとして発行された場合に実行されるファイルのパス名を表示します。基本的に、PATH環境変数をトラバースして、コマンドの最初の出現箇所を特定します。これは、Javaクラスパスを管理するための強力なツールのようにも思えます。その概念に触発されて、私はJavaクラス名を取り、クラスパスで規定されているように、クラスローダーがロードするクラスファイルの絶対パス名を表示できるJavaユーティリティの作成に着手しました。

次の使用例は、クラスローダーによってロードされるクラスのJWhich最初のオカレンスの絶対パス名を表示しますcom.clarkware.ejb.ShoppingCartBean。これはたまたまディレクトリにあります。

 > java JWhich com.clarkware.ejb.ShoppingCartBean Class'com.clarkware.ejb.ShoppingCartBean 'は' /home/mclark/classes/com/clarkware/ejb/ShoppingCartBean.class 'にあります 

次のの使用例は、クラスローダーによってロードされるクラスのJWhich最初のオカレンスの絶対パス名を表示しますjavax.servlet.http.HttpServlet。これはたまたまアーカイブファイルにパッケージ化されています。

 > java JWhichjavax.servlet.http.HttpServletクラス 'javax.servlet.http.HttpServlet'が 'file:/home/mclark/lib/servlet.jar!/javax/servlet/http/HttpServlet.class'にあります 

JWhichのしくみ

どのクラスがクラスパスで最初にロードされるかを明確に決定するには、クラスローダーの頭の中に入る必要があります。これは思ったほど難しくはありません-あなたはそれを尋ねるだけです!関連するソースコードはJWhich次のとおりです。完全なソースコードについては、「参考文献」を参照してください。

1:public class JWhich {2:3:/ ** 4:*クラスファイルの絶対パス名を出力します5:*現在のクラスパスで規定されているように指定されたクラス名を含みます6:*。 7:* 8:* @paramclassNameクラスの名前。 9:* / 10:public static void which(String className){11:12:if(!className.startsWith( "/")){13:className = "/" + className; 14:} 15:className = className.replace( '。'、 '/'); 16:className = className + ".class"; 17:18:java.net.URL classUrl = 19:new JWhich()。getClass()。getResource(className); 20:21:if(classUrl!= null){22:System.out.println( "\ nClass '" + className + 23: "' found in \ n '" + classUrl.getFile()+ "'"); 24:} else {25:System.out.println( "\ nClass '" + className + 26: "' not found in \ n '"+ 27:System.getProperty(" java.class.path ")+" '"); 28:} 29:} 30:31:public static void main(String args []){32:if(args.length > 0){33:JWhich.which(args [0]); 34:} else {35:System.err.println( "Usage:java JWhich"); 36:} 37:} 38:}

まず、クラスローダーを受け入れるために、クラス名を少しマッサージする必要があります(12〜16行目)。クラス名の前に「/」を付けると、呼び出し元のクラスのパッケージ名を暗黙的に前に付けようとするのではなく、クラスパス内でクラス名を逐語的に照合するようにクラスローダーに指示します。 「。」の各出現を変換します。 to "/"は、クラス名をクラスローダーに必要な有効なURLリソース名としてフォーマットします。

次に、適切にフォーマットされたクラス名に一致するリソースについて、クラスローダーが問い合わせられます(18〜19行目)。すべてのClassオブジェクトは、ClassLoaderそれをロードしたオブジェクトへの参照を維持するため、JWhichクラス自体をロードしたクラスローダーがここで問い合わせられます。このClass.getResource()メソッドは実際には、クラスをロードしたクラスローダーに委任し、クラスファイルリソースを読み取るためのURLを返すかnull、指定されたクラス名のクラスファイルリソースが現在のクラスパスで見つからなかった場合に返します。

最後に、指定されたクラス名を含むクラスファイルの絶対パス名が、現在のクラスパスで見つかった場合は表示されます(21〜24行目)。デバッグの補助として、クラスファイルが現在のクラスパスで見つからなかった場合は、java.class.pathシステムプロパティの値を取得して、現在のクラスパスを表示します(24〜28行目)。

この単純なコードのチャンクが、サーブレットエンジンのクラスパスを使用するJavaサーブレット、またはEJBサーバーのクラスパスを使用するEnterprise JavaBean(EJB)でどのように呼び出されるかを想像するのは簡単です。たとえば、JWhichクラスがサーブレットエンジンのカスタムクラスローダーによってロードされた場合、サーブレットエンジンのクラスローダーを使用してクラスが検索されます。サーブレットエンジンのクラスローダーがクラスを見つけることができない場合、サーブレットエンジンはその親クラスローダーに委任します。一般に、JWhichクラスローダーによってロードされると、クラスローダーまたは任意の親クラスローダーによってロードされたすべてのクラスを見つけることができます。

結論

必要性がすべての発明の母である場合、Javaクラスパスの管理を支援するツールは長い間延期されています。Java関連のニュースグループとメーリングリストには、クラスパスに関連する質問がぎっしり詰まっています。新しい開発者の参入障壁を低くして、より高いレベルの抽象化で作業を続けることができるようにする必要があります。JWhichはシンプルでありながら強力なツールであり、あらゆる環境でJavaクラスパスを習得するのに役立ちます。

Mike Clarkは、Clarkware Consultingの独立コンサルタントであり、Javaベースのアーキテクチャ、設計、およびJ2EEテクノロジを使用した開発を専門としています。彼は最近、企業間(B2B)XML交換サーバーの開発と展開を完了し、現在、J2EEパフォーマンス管理製品を構築するプロジェクトのコンサルタントを務めています。

このトピックの詳細

  • Obtain the full source code for this article

    //images.techhive.com/downloads/idge/imported/article/jvw/2000/12/jwhich.zip

  • A full-featured version of JWhich, including a classpath validator, is available at

    //www.clarkware.com/software/jwhich.zip

  • Official documentation for the Sun JDK and how it deals with the classpath for the various officially supported platforms is available at

    //java.sun.com/j2se/1.3/docs/tooldocs/findingclasses.html

  • For details on how to set the classpath on Unix and Windows platforms, see "Setting the classpath" at:
  • Unix

    //java.sun.com/j2se/1.3/docs/tooldocs/solaris/classpath.html

  • Windows

    //java.sun.com/j2se/1.3/docs/tooldocs/win32/classpath.html

  • View all previous Java Tips and submit your own

    //www.javaworld.com/javatips/jw-javatips.index.html

  • より多くのJavaトリックについては、ITworld.comの自由に加入するJavaチューターニュースレター

    //www.itworld.com/cgi-bin/subcontent12.cgi

  • JavaWorldの作者であるGeoffFriesenが司会を務める、Java初心者向けのディスカッションで発言してください。

    //www.itworld.com/jump/jw-javatip105/forums.itworld.com/[email protected]@.ee6b804/1195!skip=1125

このストーリー「JavaTip105:JWhichでクラスパスをマスターする」は、もともとJavaWorldによって公開されました。