今天在看JDBC编程的时候有个疑惑:为什么加载数据库驱动只需要下面这样的一句?它把Driver的Class对象创建出来却没有引用,这到底是几个意思?怎么看起来跟后面的代码完全是独立的,但是把它删除又会报错。
Class.forName("com.mysql.jdbc.Driver");
首先来看看Class.forName(String className)这个方法,虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都会有一个Class对象。运行程序时,JVM首先检查是否所要加载的类对应的Class对象已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。每个数组被映射为Class对象的一个类,所有具有相同元素类型和维数的数组都能共享该Class对象。一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。
如何得到Class的对象呢?常用的有两种方法:
1.调用Object类的getClass()方法来得到Class对象,这也是最常见的产生Class对象的方法。例如:
Object obj = new Object();
Class clazz = obj.getClass();
2.使用Class类中的静态forName()方法获得与字符串对应的Class对象,当执行下面的方法之后,该被加载的类中的static初始化块将会被执行。
Class clazz = Class.forName("class java.lang.Object");
下面进入源码分析部分:
既然加载的是com.mysql.jdbc.Driver这个类,那么就先看这个类,它实现了java.sql.Driver这个接口,java.sql.Driver是每个驱动程序类必须实现的接口。DriverManager会试着加载尽可能多的它可以找到的驱动程序,然后,对于任何给定连接请求,它会让每个驱动程序依次试着连接到目标URL。在加载某一Driver类时。它应该创建自己的实例并向DriverManager注册该实例。下面是com.mysql.jdbc.Driver中的静态初始化块,也就是说执行Class.forName(“com.mysql.jdbc.Driver”)之后,调用的就是这个静态初始化块中的方法。
//
// Register ourselves with the DriverManager
//
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
这里面核心的就是java.sql.DriverManager.registerDriver(new Driver())这个方法是jdk中sql包下的DriverManager类的静态方法,它接收的参数类型是java.sql.Driver,就是因为所有的数据库驱动程序都实现了java.sql.Driver接口,所以可以把com.mysql.jdbc.Driver类传进去。这也是为什么不同的数据库驱动可以往同一个DriverManager中注册的原因。
public static synchronized void registerDriver(java.sql.Driver driver)
throws SQLException {
registerDriver(driver, null);
}
继续点进去。
来到了registerDriver(java.sql.Driver driver,DriverAction da);其实就是把当前的JDBC驱动加入到registeredDrivers中。
public static synchronized void registerDriver(java.sql.Driver driver,
DriverAction da)
throws SQLException {
/* Register the driver if it has not already been added to our list */
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
// This is for compatibility with the original DriverManager
throw new NullPointerException();
}
println("registerDriver: " + driver);
}
看看registeredDrivers是DriverManager类中的静态变量,是一个用来存放已经注册的JDBC驱动的List。
// List of registered JDBC drivers
private final static CopyOnWriteArrayList registeredDrivers = new CopyOnWriteArrayList<>();
这就是一个数据库驱动加载并注册到DriverManager中的全部过程。
但是我有一个问题一直没有想明白,DriverManager是什么时候被加载到JVM中的?是怎么被初始化的?来一个简版的Driver与DriverManager就很清晰了。
DriverManagerTest类,list一定要初始化,如果没有初始化,list的初始值就是null,空指针你懂的。
public class DriverManagerTest {
static {
System.out.println("DriverManagerTest类加载完毕。。。");
}
// 一定要初始化
private static List list = new ArrayList<>();
public static void addElement() {
list.add("str1");
}
public static String getElement() {
return list.get(0);
}
}
DriverTest类
public class DriverTest {
static {
DriverManagerTest.addElement();
System.out.println("DriverTest的静态初始化块执行完毕。。。。");
}
public static void main(String[] args) throws Exception{
Class.forName("com.xiaoshan.hr.entity.DriverTest");
System.out.println(DriverManagerTest.getElement());
}
}
运行结果:
DriverManagerTest类加载完毕。。。
DriverTest的静态初始化块执行完毕。。。。
str1
程序分析:
Class.forName("com.xiaoshan.hr.entity.DriverTest");加载了DriverTest这个类到JVM中,随后执行DriverTest的静态初始化块的方法,在DriverTest的静态初始化块调用了DriverManagerTest的addElement()。噔噔噔!此时,DriverManagerTest类的静态初始化块已经执行了,说明此时DriverManagerTest类已经被加载了,然后再调用DriverManagerTest的静态方法,往它的静态成员list中添加了一个元素。最终通过静态方法getElement()可以看到list中已经加入了一个元素str1。这个就是DriverManagerTest的加载过程。所以上面的DriverManager在什么时候被加载道理是一毛一样的。
最后,欢迎点赞关注,有问题?下方留言。