起動時にプログラム側でクラスパスを設定する
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() &amp;&amp; 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}の組み立てをプログラム側に持ってきたいのだ。