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<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;
      }
  });
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值