前言

之前学习了JDK SPI的机制,本文专门讨论2个内容:

1.为什么在使用SPI后,不需要Class.forName()了?

2.SPI在JDBC中的运用。

JDBC模板代码

  1. private static final String URL = "jdbc:mysql://localhost:3306/demo?useSSL=true&useUnicode=true&characterEncoding=UTF-8";
  2. private static final String DRIVER = "com.mysql.jdbc.Driver";
  3. //加载驱动信息,使用SPI之后,不需要下面这行代码了。
  4. static {
  5. try {
  6. Class.forName(DRIVER);
  7. } catch (ClassNotFoundException e) {
  8. e.printStackTrace();
  9. }
  10. }
  11. public static void main(String[] args) throws Exception {
  12. Connection conn = DriverManager.getConnection(url, user, password);
  13. String sql = "insert into user (name, pwd) values(?,?)";
  14. Statement st = conn.createStatement();
  15. st.executeQuery(sql);
  16. }

为什么在使用SPI后,不需要Class.forName()了?

首先我们需要了解:Class.forName("com.mysql.jdbc.Driver")的作用是:

根据JVM类加载的原理,该代码会将这个字节码文件加载到虚拟机内部,

而由于类加载共有7个阶段,并且Class.forName()方法中使用了JDK反射包中Class<?> caller = Reflection.getCallerClass();

所以,Class.forName()方法不仅仅会加载Driver类,还会执行它的类初始化的过程(即静态代码块,静态变量赋值等操作)

其次我们看看为什么不需要Class.forName()了?

我们来分析一下main方法中的第一句源码:Connection conn = DriverManager.getConnection(url, user, password);

首先调用该方法前,JVM会加载DriverManager类,然后执行连接,初始化。

  1. DriverManager.Class源码
  2. /**
  3. * Load the initial JDBC drivers by checking the System property
  4. * jdbc.properties and then use the {@code ServiceLoader} mechanism
  5. * 这里清楚的说明了,该代码块会使用SPI机制进行服务发现。
  6. */
  7. static {
  8. loadInitialDrivers();
  9. println("JDBC DriverManager initialized");
  10. }

然后跟踪代码loadInitialDrivers();会发现:

  1. ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
  2. Iterator<Driver> driversIterator = loadedDrivers.iterator();
  3. /*
  4. * 省略注释
  5. */
  6. try{
  7. while(driversIterator.hasNext()) {
  8. driversIterator.next();
  9. }
  10. } catch(Throwable t) {
  11. // Do nothing
  12. }

我的上一篇博客JDK中的SPI机制中的例1和这里是一样的,因为我本来也是参考它来学习的。

根据上一篇博客里面的类加载分析,我们知道了这里DriverManager.Class的静态初始化,和显示的执行Class.forName()是一致的。

因为他们使用的类加载器分别是:

1.DriverManager.Class静态初始化内的SPI机制所使用的是:线程上下文类加载器,默认为系统类加载器AppClassLoader。

2.Class.forName()为main方法所在的类的类加载器:系统类加载器AppClassLoader。

所以这里默认是同一个类加载器来加载我们classpath下面的com.mysql.jdbc.Driver

综上:

1.在使用SPI后,不需要显示调用Class.forName()了。

2.SPI在JDBC中的运用就是如此,它使用了SPI来对实现方做了约束,并把实现独立于实现方中,JDK这样来提供了一种服务提供发现机制.

SPI在JDBC中的运用的更多相关文章

  1. JDBC中的Statement和PreparedStatement的区别

    JDBC中的Statement和PreparedStatement的区别  

  2. [转]JDBC中日期时间的处理技巧

    Java中用类java.util.Date对日期/时间做了封装,此类提供了对年.月.日.时.分.秒.毫秒以及时区的控制方法,同时也提供一些工具方法,比如日期/时间的比较,前后判断等. java.uti ...

  3. JDBC中的事务-Transaction

    事务-Transaction 某些情况下我们希望对数据库的某一操作要么整体成功,要么整体失败,经典的例子就是支付宝提现.例如我们发起了支付宝到银行卡的100元提现申请,我们希望的结果是支付宝余额减少1 ...

  4. Oracle数据库编程:在JDBC中应用Oracle

    9.在JDBC中应用Oracle: JDBC访问数据库基本步骤:          1.加载驱动          2.获取链接对象          3.创建SQL语句          4.提交S ...

  5. JDBC中的ResultSet无法多次循环的问题。

    前几天碰见了一个很奇葩的问题,使我百思不得其解,今天就写一下我遇见的问题吧,也供大家参考,别和我犯同样的毛病. 首先说下jdbc,jdbc是java是一种用于执行SQL语句的Java API,从jdb ...

  6. 在JDBC中使用Java8的日期LocalDate、LocalDateTime

    在实体Entity里面,可以使用java.sql.Date.java.sql.Timestamp.java.util.Date来映射到数据库的date.timestamp.datetime等字段 但是 ...

  7. 使用JDBC中的出现的乱码和查询无结果问题

    使用JDBC中的问题 连接的后出现查询结果是乱码. 1.可能是代码的编码与数据库的编码不同 ​ 有可以将二者都设置为UTF-8 2.如果比较懒得话可以只设代码为UTF-8 mysql 连接url中us ...

  8. 转:JDBC中关于PreparedStatement.setObject的一些细节说明

    原文地址:https://blog.csdn.net/zhiyangxuzs/article/details/78657235 JDBC中PreparedStatement.setObject(ind ...

  9. 一、DAO设计模式 二、DAO设计模式的优化 三、JDBC中的事务,连接池的使用

    一.DAO设计模式概述###<1>概念 DAO,Data Access Object ,用于访问数据库的对象. 位于业务逻辑和数据持久化层之间,实现对数据持久化层的访问![](1.png) ...

随机推荐

  1. Metasploit用法详解

    Metasploit简介 1. Auxiliaries(辅助模块) 该模块不会直接在测试者和目标主机之间建立访问,它们只负责执行扫描.嗅探.指纹识别等相关功能以辅助渗透测试. 2. Exploit(漏 ...

  2. CountDownLatch能不能在多个线程上添加await?

    在CountDownLatch类的使用过程中,发现了一个很奇怪的现象: CountDownLatch countDownLatch = new CountDownLatch(2); Runnable ...

  3. JDK1.8源码(八)——java.util.HashMap类

    https://www.cnblogs.com/javastack/p/12801870.html https://www.cnblogs.com/chanshuyi/p/java_collectio ...

  4. PyQt5 笔记

    一.简介 pyqt5做为Python的一个模块,它有620多个类和6000个函数和方法.这是一个跨平台的工具包,它可以运行在所有主要的操作系统,包括UNIX,Windows,Mac OS.pyqt5是 ...

  5. 20210714 noip15

    考前 mtr 中午拿着笔记本改题(Orz),一点多发现 13.50 有比赛(截止 12 点都没放出来),赶紧睡.13.40 到了学校,巨瞌睡,洗了把脸到机房发现推迟到 14.30 了,wcnm 趴在桌 ...

  6. Python习题集(八)

    每天一习题,提升Python不是问题!!有更简洁的写法请评论告知我! https://www.cnblogs.com/poloyy/category/1676599.html 题目 要求:判断数组元素 ...

  7. 第05课:GDB 常用命令详解(上)

    本课的核心内容如下: run 命令 continue 命令 break 命令 backtrace 与 frame 命令 info break.enable.disable 和 delete 命令 li ...

  8. sqlmap --eval 用法

    今天查资料发现 sqlmap 有一个 --eval 的参数 --eval=EVALCODE Evaluate provided Python code before the request (e.g. ...

  9. Xilinx约束学习笔记(三)—— 时序概念

    3. 时序概念 发现对于时序基础的介绍这一块,Intel 的文档竟然要比 Xilinx 的详细,因此引用了很多 Intel 的文档内容. 3.1 术语 发送沿(launch edge),指用来发送数据 ...

  10. 【第七篇】- Git 分支管理之Spring Cloud直播商城 b2b2c电子商务技术总结

    ​ Git 分支管理 几乎每一种版本控制系统都以某种形式支持分支.使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作. 有人把 Git 的分支模型称为必杀技特性,而正是因为它,将 ...