Class Loader について †
- Class Loader は、その名の通り Class を load するもの
- Java の Class Loader は、親子関係になっている
- Bootstrap Class Loader は、Java VM が読み込むクラス
- System Class Loader は、Classpath に含まれるクラスを担当する
- My Class Loader が自作の Class Loader
- Class を探す順序
- まず、親に Class の load を依頼する
- 親が load できないときに、自分で load する
- つまり、Bootstrap Class Loader で解決できないと、System Class Loader で解決しようとし、それでもダメだと My Class Loader が使われる。
- My Class Loader を使うには?
- 独自のクラスローダーからロードされたクラスの中では、そのクラスローダが使われる。
- つまり、Classpath に入っていないクラスを呼び出してやると、以降の Class の load では、 My Classloader が使われる。
- Thread.currentThread().setContextClassLoader?(cl) で、My Class Loader を指定してやっても、Classpath に入っているクラスだと、System Class Loader から呼び出されてしまう。
サンプルプログラム †
- サンプルプログラムの概要
- BootStrap?プロジェクトと、ClassLoaderExam?プロジェクトには依存関係は設定せず、通常の方法では BootStrap? から Action クラスが見えないようにする。
- また、mysql-connector-java-5.1.5-bin.jar は、どちらのプロジェクトの Classpath にも入っていない。
- BootStrap? に main() が有り、ここから起動する。
- BootStrap?#main() で、ClassLoaderExam?\bin と ClassLoaderExam?\mysql-connector-java-5.1.5-bin.jar を含む myClassLoader? を作成する。
- myClassLoader? を使って Action#perform() を起動する。
- Action#perform() 内で、JDBCドライバを使って RDB にアクセスする。
- 普通に Class#forName() したら、JDBCドライバは Classpath に入っていないので、load() できないはず
- しかし、Action クラスは、myClassLoader? を使ってロードされたので、Action クラス内で Class#forName() とやると、myClassLoader? が使われ、load()できる。
- BootStrap?.jara
package com.snail.example;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class BootStrap {
public static void main(String[] args) {
try {
File jarFile = new File(
"../ClassLoaderExam/mysql-connector-java-5.1.5-bin.jar");
File loader = new File("../ClassLoaderExam/bin");
ClassLoader parent = ClassLoader.getSystemClassLoader();
URLClassLoader myClassLoader = new URLClassLoader(new URL[] {
jarFile.toURI().toURL(), loader.toURI().toURL()
}, parent);
Class<?> actionClass = Class.forName("com.snail.example.Action", true,
myClassLoader);
Object actionObject = actionClass.newInstance();
Method performMethod = actionClass.getMethod("perform");
performMethod.invoke(actionObject);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
- Action.java
package com.snail.example;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Action {
public Action() {
super();
}
public void perform() {
System.out.println("start perform");
System.out.println("Class Loader of Action Class = "
+ this.getClass().getClassLoader() );
try {
Class<?> driver = Class.forName("com.mysql.jdbc.Driver");
System.out.println("Class Loader of JDBC Driver = "
+ driver.getClassLoader() + "\n");
String url = "jdbc:mysql://192.168.1.6:3306/test?useUnicode=true&characterEncoding=utf-8";
String user = "test";
String pass = "pass";
Connection con = DriverManager.getConnection(url, user, pass);
PreparedStatement ptst = con.prepareStatement("SELECT * FROM books");
ResultSet res = ptst.executeQuery();
while (res.next()) {
String isbn = res.getString(1);
String title = res.getString(2);
String author = res.getString(3);
System.out.println(isbn + "," + title + "," + author);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
実行結果 †
start perform
Class Loader of Action Class = java.net.URLClassLoader@10b30a7
Class Loader of JDBC Driver = java.net.URLClassLoader@10b30a7
1234,品格本作者の品格,関西鷽子
5678,リアルかごめかごめ,鈴木洋介
90XX,六星占術によるUB313星人の運命 平成20年版,細木数乃子
子が先 †
- Tomcat の WebClassLoader? を使えば、最初に、子(自分)配下から Class を探すようにできる。
- ちゃんと考えて作らないと、クラスのアンロード (GC) が適切に行われないので、余り自分で変な振る舞いをする Class Loader は作らない方が吉かも・・・
- Tomcat も最近になるまで「メモリリーク」問題を抱えていた
- 最近の Tomcat は、安定してきているので、こういう Class Loader が欲しいなら、Tomcat のものを使わせて貰うのが良さげ
Java#JavaSE