现在的位置: 首页 > 综合 > 正文

为什么需要Class.forName(“com.mysql.jdbc.Driver”)

2018年01月25日 ⁄ 综合 ⁄ 共 2971字 ⁄ 字号 评论关闭

在使用传统的JDBC连接数据库的时候,总是需要这一句(以MySQL为例):

Class.forName("com.mysql.jdbc.Driver");   

以前我也没深究,只是看网上的例子都这么写,实际上也跑通了,于是便懒得去管内部原理。不过大概还是清楚的,知道这句话是向DriverManage注册了一个MySQL的JDBC Driver。

但为什么要用Class.forName这样看上去不是很优雅的方式呢?

网上还流传了一个这样的版本Class.forName("com.mysql.jdbc.Driver").newInstance(),似乎有点儿多此一举。

经过实验,我发现用com.mysql.jdbc.Driver driver = new com.mysql.jdbc.Driver() 也是可以的,但是只声明

com.mysql.jdbc.Driver driver = null ,而不实例化却又是不行的。

那么Driver的注册到底是在类的初始化时进行的,还是在类的对象初始化时进行的呢? 我也不知道,最好的办法还是看源码:

 

package com.mysql.jdbc;

import java.sql.DriverManager;
import java.sql.SQLException;

// Referenced classes of package com.mysql.jdbc:
//            NonRegisteringDriver

public class Driver extends NonRegisteringDriver
{

    public Driver()
        throws SQLException
    {
    }

    static
    {
        try
        {
            DriverManager.registerDriver(new Driver());
        }
        catch(SQLException E)
        {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

源码之前没秘密,com.mysql.jdbc.Driver很简单,就是红色的那句,看来是在类的static block里面做的初始化。

那么我们只要搞清楚在java里面,static block执行的时机就可以清楚来龙去脉了。

还是做一个实验吧:package com.javaye;

class A{
     static{
               System.out.println("Class A loaded");
      }
     public A(){
             System.out.println("create a instance of A");
      }
}


public class Main {
 
      public static void main(String[] args) throws Exception{
                 Class.forName("com.javaye.A");
     }
}
 

打印结果:“Class A loaded”
 

这说明Class.forName可以使类的static block中的代码得到执行。

然后,我们在修改成下面这样:

package com.javaye;

class A{
 static{
  System.out.println("Class A loaded");
 }
 public A(){
  System.out.println("create a instance of A");
 }
}
public class Main {
 
 public static void main(String[] args) throws Exception{
  com.javaye.A a = null;
  
 }
}
 

发现没有打印任何东西,这说明只是声明某个类的变量,是不会使static block的到执行的。

再改一下:

package com.javaye;

class A{
 static{
  System.out.println("Class A loaded");
 }
 public A(){
  System.out.println("create a instance of A");
 }
}
public class Main {
 
 public static void main(String[] args) throws Exception{
  com.javaye.A a = new com.javaye.A();
  com.javaye.A a2 = new com.javaye.A();
 }
}

输出结果:

Class A loaded
create a instance of A
create a instance of A
 

这说明实例化一个类的话,static block 也会被执行,而且只会被执行一遍。

如果仍有兴趣,还可以探索一下Driver的注册机制:

public static synchronized void registerDriver(java.sql.Driver driver)
 throws SQLException {
 if (!initialized) {
     initialize();
 }
     
 DriverInfo di = new DriverInfo();
 di.driver = driver;
 di.driverClass = driver.getClass();
 di.driverClassName = di.driverClass.getName();
 drivers.addElement(di);    //drivers 是一个vector,保存着被注册的driver.
 println("registerDriver: " + di);
 

}

getConnection就是要从drivers里面挑出一个合适的数据库driver:

for (int i = 0; i < drivers.size(); i++) {
     DriverInfo di = (DriverInfo)drivers.elementAt(i);
     
     // If the caller does not have permission to load the driver then
     // skip it.
     if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
  println("    skipping: " + di);
  continue;
     }
     try {
  println("    trying " + di);
  Connection result = di.driver.connect(url, info);
  if (result != null) {
      // Success!
      println("getConnection returning " + di);
      return (result);
  }
     } catch (SQLException ex) {
  if (reason == null) {
      reason = ex;
  }
}

抱歉!评论已关闭.