Class.forName(“org.h2.Driver”)は何をやっているのか
Class.forName(“org.h2.Driver”)が H2データベースドライバを
JVMに読み込んでいることはネットや本で解説されているが、
具体的に何をしているかまではわからない。
そこでいろいろ調べてみた。
クラスをファイルシステムからロードする
(1) ブートストラップ・クラスローダ
(2) プラットフォーム・クラスローダ
(3) システム・クラスローダ(アプリケーション・クラスローダ)
(1) JavaSEの主要なクラスをロードする。たとえば、java.lang.String
(2) JavaSEのクラスをロードする。例、java.net.http.HttpClient
(3) 開発者が作成したクラスをロードする。
クラスローダを調べる
以下のようにすれば、クラスローダを調べることができる。
public class ClassLoaderTest {
public static void main(String[] args) {
Hero h = new Hero();
Class<?> clazz = Hero.class;
System.out.println(clazz.getClassLoader());
}
}
// jdk.internal.loader.ClassLoaders$AppClassLoader@42110406
クラスがロードされるタイミング
(1) スタティックなメンバーへのアクセス
(2) Classクラスの forName()メソッド呼び出し
(3) new演算子によるインスタンス生成
(4) Constructorクラスの newInstance()メソッド呼び出し
Class.forName()で何がおこなわれているか — static初期化ブロック
Class.forName()によって、クラスがメモリにロードされることがわかったが、
ロードされたタイミングで処理を仕込むことができる。
ロードされるクラスに static{}ブロックを作成し、そこに処理を
書いておくと、ロード時にそれが実行される。
以下のようにして試してみる。
srcに demoパッケージを作成し、Pqrクラスを作成する。
package demo;
public class Pqr {
static {
System.out.println("in static!");
}
{
System.out.println("in instance!");
}
}
static{} — static初期化ブロックは、クラスがクラスローダによってロードされた時点で動作する。
{} — インスタンス初期化ブロック は、インスタンスが生成される直前で動作する。
試してみる。
package demo;
public class DemoClass {
public static void main(String[] args) {
Pqr obj = new Pqr();
}
}
// 実行例
// in static!
// in instance!
static初期化ブロック、インスタンス初期化ブロックともに実行されている。
package demo;
public class DemoClass {
public static void main(String[] args) throws Exception {
// Pqr obj = new Pqr();
Class.forName("demo.Pqr");
}
}
// 実行例
// in static!
static初期化ブロックのみが実行されている。
org.h2.Driverクラスはどうなっているか
Driver.java
package org.h2;
public class Driver implements java.sql.Driver, JdbcDriverBackwardsCompat {
private static final Driver INSTANCE = new Driver();
private static final String DEFAULT_URL = "jdbc:default:connection";
private static final ThreadLocal<Connection> DEFAULT_CONNECTION =
new ThreadLocal<>();
private static boolean registered;
static {
load();
}
...
}
static初期化ブロックでは、load()メソッドがあるだけである。
その load()メソッドは以下である。
Driver.java (一部)
...
public static synchronized Driver load() {
try {
if (!registered) {
registered = true;
DriverManager.registerDriver(INSTANCE);
}
} catch (SQLException e) {
DbException.traceThrowable(e);
}
return INSTANCE;
}
...
DriverManagetクラスの registerDriver()メソッドを呼び出し、
引数に自身のインスタンスを渡して、自分自身のインスタンスを
登録している。
であるから、以下のコードでも DriverManagerクラスに H2ドライバーを
登録することができる。
DAOクラス
try {
DriverManager.registerDriver(new org.h2.Driver());
System.out.println("DBドライバーを登録しました。");
} catch (SQLException e) {
throw new IllegalStateException("ドライバーを登録できません!");
}
この場合は、コンパイル時に org.h2.Driverクラスが必要である。
しかし、以下のようにすると、実行時に org.h2.Driverクラスがあればよい。
try {
Class.forName("org.h2.Driver");
} catch (ClassNotFoundException e) {
throw new IllegalStateException("ドライバファイルが見つかりません");
}
参考
8.1 クラスローダーの仕組みとClassクラス(クラスのライフサイクル、ClassLoaderなど)~Java Advanced編
カテゴリー: Java, memo
タグ: Class.forName, DriverManager, H2ドライバー, org.h2.Driver, sql, sql.Driver
カウント: 189