2008.07.03

ある特定のパッケージ配下のクラスを自動でインスタンス化する方法

今回は、ある特定のパッケージ配下のクラスを自動でインスタンス化し、
アプリケーションで保持する方法についてご紹介します。

この方法を利用すると、ある特定の役割を持ったクラスを
アプリケーション起動時にロードしてしまい、
シングルトンで管理したいという場合に役に立ちます。
もし、管理したいクラスを設定ファイル等に記載する方法を取っていた場合、
管理したいクラスが増減する毎に、設定ファイルの修正が必要になってしまいます。
これは非常に面倒です。
しかし、今回ご紹介する方法を利用すれば、
管理したいクラスが増減しても何も修正する必要がなくなるというわけです。

-----------------(以下、説明)-----------------------

まず、一括でインスタンス化したいクラスが配置されている
パッケージを名を指定します。

------------------------------------------------------
String sPackage = "hoge.app.form";
------------------------------------------------------


これを"/"(スラッシュ)区切りのパスに変換します。

------------------------------------------------------
String sResourcePath = sPackage.replace(".", "/");
------------------------------------------------------
"hoge.app.form" ⇒ "hoge/app/form"


次に、ClassオブジェクトをロードするClassLoaderを指定して、
そのClassLoaderのgetResourceメソッドを利用して、
先ほどのパッケージのパスを引数として渡します。

------------------------------------------------------
// ここで使用するClassLoaderは、現在実行中のスレッドから取得した
// コンテキスト ClassLoader を利用するものとします。
URL resourceUrl = classLoadar.getResource(sResourcePath);
------------------------------------------------------
こうすることにより、指定したパッケージのファイルシステム上のパスが取得できます。
※この説明では、ファイルシステム上に展開されているクラスを対象としています。
 jarファイル内のクラスは対象としておりません。


取得したパッケージのファイルパスを利用して、Fileオブジェクトを生成します。
※取得したFileオブジェクトは、パッケージをあらわすものなので、実体はフォルダとなります。
------------------------------------------------------
File file = new File(resourceUrl.getFile());
------------------------------------------------------


取得したパッケージを表すFileオブジェクトから、
パッケージ配下のファイルを表すFileオブジェクトを取得します。
※この説明では、パッケージ配下にはclassファイルしか存在しなことを前提としております。
------------------------------------------------------
File[] classFiles = file.listFiles();
------------------------------------------------------


取得したFileオブジェクトからファイル名を取得して、
拡張子".class"を除いたファイル名と、最初に指定したパッケージ名を結合し、
インスタンス化するクラスの完全指定名を取得する。
最後に、取得したクラス名を利用してクラスをインスタンス化します。
------------------------------------------------------
Map map = new HashMap();
for (int i1 = 0; i1 < classFiles.length; i1++) {
  String sFileName = classFiles[i1].getName();
  // 拡張子".class"を除いたファイル名と、パッケージ名を結合する。
  String sClassName = sPackage + "." + sFileName.substring(0, sFileName.indexOf(".class"));
  // 取得した完全指定されたクラス名にてクラスをインスタンス化する。
  map.put(sClassName, Class.forName(sClassName).newInstance());
}
------------------------------------------------------

上記の説明では、対象のパッケージ配下には、
クラスファイルしか存在しないパターンとなっていますが、
実際の開発では、サブパッケージが存在するケースがほとんどかと思います。
なので、リンクしてあるサンプルプログラムは、
サブパッケージ配下も検索してクラスファイルをロードするようにしてあるので、
参照してみてください。

サンプルプログラムをダウンロード

コメントを投稿

(いままで、ここでコメントしたことがないときは、コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。承認されるまではコメントは表示されません。そのときはしばらく待ってください。)

photo
ykato