起動時にプログラム側でクラスパスを設定する

Winstoneのコード読みしたときの収穫。


環境変数javaの起動引数にクラスパスを指定しないで,プログラム側でクラスローダ作ってしまったほうがいいのではないか。と言うのは,バッチ処理などmain関数を持ってるプログラムの起動シェルを楽したいためだ。
案外簡単で,こんな感じ(カレントディレクトリ直下の"./lib"ディレクトリにある*.jarとか*.zipをクラスパスに含める)。

private ClassLoader getCommonClassLoader() throws Exception {
  List jars = new ArrayList();
  String commonLibCLFolder = "./lib";
  File libFolder = new File(commonLibCLFolder);
  if (libFolder.exists() && libFolder.isDirectory()) {
    File children[] = libFolder.listFiles();
    for (int n = 0; n < children.length; n++)
      if (children[n].getName().endsWith(".jar")
          || children[n].getName().endsWith(".zip")) {
        jars.add(children[n].toURL());
     }
  }
  return new URLClassLoader((URL[]) jars.toArray(new URL[0]),
                            getClass().getClassLoader());
}

上記処理で取得したクラスローダを使って,Class.forName()でクラスを見つけてあげる。

Class.forName("foo.bar.HogeHoge", true, classLoader);

HogeHogeクラス中では,Class.forName(String)だけでも同じクラスローダを共有してくれてる。なかなか良い感じ。
でも,クラスローダはうかつに手を出すと痛い目あいそうだから,いろいろ調べておかないと。


たとえば,「Thread.currentThread().setContextClassLoader();」を設定すべきかどうかは,調べ中だ。


(補足)やりたいことは,起動シェルでこんな事書いてるんだけど,

for i in `ls -ar "${LIB_DIR}"/*.jar`
do
  if [ -f "${i}" ]; then
    if [ -z "${LOCAL_CLASSPATH}" ]; then
      LOCAL_CLASSPATH="${i}"
    else
      LOCAL_CLASSPATH="${i}":"${LOCAL_CLASSPATH}"
    fi
  fi
done

${JAVA_HOME}/bin/java -cp ${LOCAL_CLASSPATH} ...

この${LOCAL_CLASSPATH}の組み立てをプログラム側に持ってきたいのだ。