简单解释一下,以下源代码参考自JDK8和MySQL-Connector-8.0.15。
注册JDBC驱动有三种方式:
第一种:
Class.forName(className);
第二种:
DriverManager.registerDriver(driver);
DriverManager.registerDriver(driver, driverAction);
第三种:
System.setProperty("jdbc.drivers", className);
分别看一下它们的源码。
com.mysql.cj.jdbc.Driver的静态初始化块是这样的:
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
可以看到它在被加载的时候实际上调用了java.sql.DriverManager.registerDriver(driver)
看一下这个静态方法的源码:
public static synchronized void registerDriver(java.sql.Driver driver) throws SQLException {
registerDriver(driver, null);
}
public static synchronized void registerDriver(java.sql.Driver driver, DriverAction da) throws SQLException {
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
throw new NullPointerException();
}
println("registerDriver: " + driver);
}
其中的registeredDrivers是一个CopyOnWriteArrayList,它的每一项元素都存储了一个Driver实例,它们会在getConnection中被遍历,然后调用driver.connect(url, info)来获取Connection实例。
再看一下DriverManager 的静态初始化块:
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
private static void loadInitialDrivers() {
String drivers;
try {
drivers = AccessController.doPrivileged(new PrivilegedAction() {
public String run() {
return System.getProperty("jdbc.drivers");
}
});
} catch (Exception ex) {
drivers = null;
}
AccessController.doPrivileged( ... );
println("DriverManager.initialize: jdbc.drivers = " + drivers);
if (drivers == null || drivers.equals("")) {
return;
}
String[] driversList = drivers.split(":");
println("number of Drivers:" + driversList.length);
for (String aDriver : driversList) {
try {
println("DriverManager.Initialize: loading " + aDriver);
Class.forName(aDriver, true, ClassLoader.getSystemClassLoader());
} catch (Exception ex) {
println("DriverManager.Initialize: load failed: " + ex);
}
}
}
可以看到,在DriverManager被加载的时候,会调用System.getProperty("jdbc.drivers")然后对其中以':'为间隔的每一个Driver类名为参数,调用Class.forName(className),当我们调用System.setProperty("jdbc.drivers", className)的时候就会影响System.getProperty("jdbc.drivers")的返回结果。
好了,现在注册JDBC驱动的方式与原理基本讲完了。
看一下区别:
第三种方式只能在DriverManager的初始化块中生效,若已经被提前加载,则这次注册是不会发挥作用的。
第二种方式是DriverManager定义的静态方式,调用必然生效,除非发生异常。
第一种方式依赖Driver的具体实现,尽管它本质上还是使用了第二种的静态方法,而第二种的参数是一个Driver的实例,所以静态初始化块中的代码也还是会被执行。所以第二种和第一种这两种注册方式其实没有太大区别。
但是也还是有所区别的:
Class.forName(className)使用了反射,略微影响效率,但是由于以字符串为参数,因此可以将JDBC驱动配置在xml等文件中,而这种注册方法是在java.sql.Driver的javadoc中被提倡的:/**
*
When a Driver class is loaded, it should create an instance of
* itself and register it with the DriverManager. This means that a
* user can load and register a driver by calling:
*
* {@code Class.forName("foo.bah.Driver")}
*
*/