[关闭]
@pastqing 2015-05-28T11:45:23.000000Z 字数 2810 阅读 2140

JDBC Driver 加载过程分析

java


在连接数据库的时候,需要加载相关数据库的驱动,加载驱动的方式有若干种,本文分析几种常见加载方式的具体过程。

Class.forName(String driverName)

以mysql为例, 加载驱动的时候我们经常会这样写:

  1. Class.forName(driverName);
  2. Connection conn = DriverManager.getConnection();

先来分析一下Class.forName(String className)会发生什么。
阅读一下源码:

  1. public static Class<?> forName(String className)
  2. throws ClassNotFoundException {
  3. Class<?> caller = Reflection.getCallerClass();
  4. return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
  5. }

调用Class.forName(String className)时会调用forName0, 这个方法里面多了很多参数, 他们分别代表什么意思呢:

  1. private static native Class<?> forName0(
  2. String name,
  3. boolean initialize,
  4. ClassLoader loader,
  5. Class<?> caller)throws ClassNotFoundException;

我们关注一下第二个参数initialize, 它的意思是否初始化该类。也就是说在调用Class.forName("com.mysql.jdbc.Driver")会发生驱动类的初始化。我们再看看mysql驱动类(driver):

  1. static {
  2. try {
  3. java.sql.DriverManager.registerDriver(new Driver());
  4. } catch (SQLException E) {
  5. throw new RuntimeException("Can't register driver!");
  6. }
  7. }

在Driver类中,发现了一段静态块,初始化这个类的时候会调用这个静态块,那么DriverManager.registerDriver(new Driver())会发生呢?

  1. public static synchronized void registerDriver(java.sql.Driver driver)
  2. throws SQLException {
  3. /* Register the driver if it has not already been added to our list */
  4. if(driver != null) {
  5. registeredDrivers.addIfAbsent(new DriverInfo(driver));
  6. } else {
  7. // This is for compatibility with the original DriverManager
  8. throw new NullPointerException();
  9. }
  10. println("registerDriver: " + driver);
  11. }

registerDriver方法会生成一个DriverInfo对象, 并将它添加到一个CopyOnWriteArrayList类型的list中去。CopyOnWriteArrayList是一种适用于高并发中读操作多的集合类型。

以上的所有操作就完成了一个驱动的注册,为后面我们DriverManager.getConnection()打下基础
下面我们看看DriverManager.getConnection()是如何实现的,这里我们截取一段代码:

  1. for(DriverInfo aDriver : registeredDrivers) {
  2. if(isDriverAllowed(aDriver.driver, callerCL)) {
  3. try {
  4. println(" trying " + aDriver.driver.getClass().getName());
  5. Connection con = aDriver.driver.connect(url, info);
  6. if (con != null) {
  7. println("getConnection returning " + aDriver.driver.getClass().getName());
  8. return (con);
  9. }
  10. } catch (SQLException ex) {
  11. if (reason == null) {
  12. reason = ex;
  13. }
  14. }
  15. } else {
  16. println(" skipping: " + aDriver.getClass().getName());
  17. }
  18. }

我们可以看到,getConnection()其实就是遍历之前的CopyOnWriteArrayList列表,找到所有注册过的驱动,并打开连接。下面我们做个测试:

  1. public class DemoDriver {
  2. public static void main(String[] args) {
  3. final String dbName = "root";
  4. final String dbPass = "123";
  5. final String dbURL = "jdbc:mysql://192.168.109.29:3306/educationcloudpayment";
  6. try {
  7. //加载mysql
  8. Class.forName("com.mysql.jdbc.Driver");
  9. //加载sqlserver
  10. Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
  11. //将日志信息重定向到标准输出
  12. DriverManager.setLogWriter(new java.io.PrintWriter(System.out));
  13. //
  14. DriverManager.getConnection(dbURL, dbName, dbPass);
  15. } catch (ClassNotFoundException e) {
  16. e.printStackTrace();
  17. } catch (SQLException e) {
  18. e.printStackTrace();
  19. }
  20. }

这里我们分别加载了mysql和sqlserver两个驱动,从日志输出可以看出其遍历过程。
下面我们在看看Apache Commons DbUtils是怎样实现载入驱动的。
Apache Commons Dbutils loadDriver

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注