从Class.forName说起
查看com.mysql.jdbc.Driver的注释,当一个Driver类被加载的时候,它需要创建自己的一个实例,并且注册到DriverManager中。
Class.forName("com.mysql.jdbc.Driver")会触发类加载,及静态块的初始化。
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
}
另外,DriverManager有个静态块,通过jdbc.properties 及ServiceLoader注册Driver。
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
private static void loadInitialDrivers() {
String drivers;
// 通过系统配置注册
try {
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("jdbc.drivers");
}
});
} catch (Exception ex) {
drivers = null;
}
// 通过ServiceLoader注册
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
}
return null;
}
});
查看mysql-connector-java-5.1.39.jar!/META-INF/services/java.sql.Driver文件内容
com.mysql.jdbc.Driver
com.mysql.fabric.jdbc.FabricMySQLDriver
注:AccessController、ServiceLoader自行Google。
Driver的处理
将MySQL的Driver对象放入到java.sql.DriverManager#registeredDrivers中,它是一个CopyOnWriteArrayList对象。
public static synchronized void registerDriver(java.sql.Driver driver,
DriverAction da)
throws SQLException {
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
// This is for compatibility with the original DriverManager
throw new NullPointerException();
}
}
打印Driver
public class DriverTest {
public static void main(String[] args) {
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()){
System.out.println(drivers.nextElement().toString());
}
}
}
com.mysql.jdbc.Driver@6193b845
com.mysql.fabric.jdbc.FabricMySQLDriver@433c675d
org.h2.Driver@439f5b3d
com.alibaba.druid.proxy.DruidDriver@533ddba
com.alibaba.druid.mock.MockDriver@aec6354
Connection获取
java.sql.DriverManager#getConnection(java.lang.String, java.util.Properties, java.lang.Class<?>)
for(DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
// Success!
println("getConnection returning " + aDriver.driver.getClass().getName());
//成功获取连接,就返回。
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
// 最后没有找到抛出异常
// if we got here nobody could connect.
if (reason != null) {
println("getConnection failed: " + reason);
throw reason;
}
在获取连接的时候,会获取第一个能成功连接的Connection,如果注册多个MySQL Driver,仅仅会使用第一个。
参考
http://dustin.iteye.com/blog/44291
http://www.dengshenyu.com/java/2017/06/24/jdbc-basic.html