Class.forName做了什么
我们在用JDBC的时候,总是会写一句
Class.forName("com.mysql.cj.jdbc.Driver");
这里以mysql驱动为例,其他驱动都类似。
这一步会使用类加载器加载对应的驱动,并执行com.mysql.cj.jdbc.Driver的静态代码块。
进入com.mysql.cj.jdbc.Driver
静态代码块中完成了驱动的注册,也就是new了一个自身的实例,并注册到DriverManager中
DriverManager.registerDriver(new Driver());
进入DriverManager类,registerDriver方法
registeredDrivers是一个CopyOnWriteArrayList,保存所有注册过的驱动
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
DriverManger.getConnection是怎么获取连接的
DriverManger类的getConnection方法
遍历驱动list,逐个执行connect方法,如果非空,返回当前connection。
for(DriverInfo aDriver : registeredDrivers) {
try {
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
}
JDBC和SPI
如果去掉Class.forName,程序也能正常运行(JDBC4以后)。
首先看mysql驱动的jar包,META-INF/services下有个文件,文件名是java.sql.Driver,文件内容是com.mysql.cj.jdbc.Driver。
再看DriverManager类的静态代码块,调用了loadInitialDrivers方法。
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
进入loadInitialDrivers方法
使用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) {
// Do nothing
}
return null;
}
});