我们在用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() { public Void run() { ServiceLoader loadedDrivers = ServiceLoader.load(Driver.class); Iterator driversIterator = loadedDrivers.iterator(); try{ while(driversIterator.hasNext()) { driversIterator.next(); } } catch(Throwable t) { // Do nothing } return null; } });
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)