JDBC和SPI

JDBC和SPI,第1张

JDBC和SPI 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() {
      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;
      }
  });

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/zaji/5686326.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存