Class.forName で DB アクセスできるようになる理由
Java の研修で DB(だいたいMDBかな) にアクセスするプログラムを作ることになったとき、講師はほぼ 100% 「JDBC Driver を使用するためには Class.forName を使用します」と言うはず。ただ、呪文のごとく。
で、Class.forName の API を見てみる。
forName(String name, boolean initialize, ClassLoader loader)
指定されたクラスローダを使って、指定された文字列名を持つクラスまたはインタフェースに関連付けられた Class オブジェクトを返します
そして疑問が生まれる。「クラスをロードするだけでなんでDBにアクセスできるようになるの?」と。
講師はなぜできるかは説明しない。分かってないってことは無いと思うけど「まだ初心者だから覚えとけばいい」的な感じだろう。
けど、ここは言わせてもらう!
説明すべきだ!
おかげで今になってようやく理解できた。特に必要なかったのもあるけど、ふと気になって調べてみた。
んで、こういう事(間違ってたら恥ずかしいから早く教えてください)。
各ベンダの JDBC Driver は java.sql.Driver を実装している必要があり、その実装クラスは static initializer で java.sql.DriverManager.registerDriver(java.sql.Driver) を使って登録している。
Class.forName -> static initializer -> DriverManager.registerDriver って流れ。あとは DriverManager を経由して各 Driver にアクセスして使用する。
ついでにいくつかの JDBC Driver のソースを確認してみた。
sun
JDBC Driver の登録
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
static initializer
public class JdbcOdbcDriver extends JdbcOdbcObject implements JdbcOdbcDriverInterface { //-------------------------------------------------------------------- // Static method to be executed when the class is loaded. //-------------------------------------------------------------------- static { JdbcOdbcTracer tracer1 = new JdbcOdbcTracer(); if (tracer1.isTracing ()) { tracer1.trace ("JdbcOdbcDriver class loaded"); } JdbcOdbcDriver driver = new JdbcOdbcDriver (); // Attempt to register the driver try { DriverManager.registerDriver (driver); } catch (SQLException ex) { if (tracer1.isTracing ()) { tracer1.trace ("Unable to register driver"); } } }
MySQL
JDBC Driver の登録
Class.forName("com.mysql.jdbc.Driver");
static initializer
public class Driver extends NonRegisteringDriver implements java.sql.Driver { // ~ Static fields/initializers // --------------------------------------------- // // Register ourselves with the DriverManager // static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } }
PostgreSQL
JDBC Driver の登録
Class.forName("org.postgresql.Driver");
static initializer
public class Driver implements java.sql.Driver { // make these public so they can be used in setLogLevel below public static final int DEBUG = 2; public static final int INFO = 1; private static final Logger logger = new Logger(); private static boolean logLevelSet = false; static { try { // moved the registerDriver from the constructor to here // because some clients call the driver themselves (I know, as // my early jdbc work did - and that was based on other examples). // Placing it here, means that the driver is registered once only. java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException e) { e.printStackTrace(); } }