【JVM】JDBC案例打破双亲委派机制


🐌个人主页: 🐌 叶落闲庭

💨我的专栏:💨
c语言
数据结构
javaEE
操作系统
Redis

石可破也,而不可夺坚;丹可磨也,而不可夺赤。


JVM

打破双亲委派机制(JDBC案例)

JDBC的这个框架的目的是在Java中操作数据库,在他的设计的核心思想中不希望出现具体的数据库的语法,提高它的泛用性,将来对接任何数据库都会比较容易,在JDBC中,设计了一个DriverManager的类,这个类会去管理在jar包中的引入的数据库的驱动,比如要使用mysql数据库,那么就会添加一个mysql的驱动jar包,DriverManager会负责把驱动jar包加载进来,这样就可以连接mysql的数据库了,要想连接其他类型的数据库,只需将jar包替换成其他数据库的即可,这样DriverManager就可以对接不同的数据库,并且在代码方面是统一的,但是在DriverManager去加载驱动jar包的类的过程中打破了双亲委派机制:

DriverManager这个类是jdk自己提供的,位于rt.jar这个jar包中,所以这个类就会由启动类加载器加载,而mysql的驱动jar包是由应用程序类加载器加载的,当启动类加载器加载完DriverManager类后,又将DriverManager委派给应用程序类加载器去加载mysql的驱动jar包,这就违反了双亲委派机制



问题1:DriverManager怎么知道jar包中要加载的驱动在哪?

SPI机制

  • spi全称为Service Provider Interface ,是JDK内置的一种服务提供发现机制
  • spi工作原理:

以jdbc连接数据库为例:

  • 1.在ClassPath路径下的META-INF/services文件夹中,以接口的全限定名来命名文件名,对应的文件里写该接口的实现,这个文件的名字就是当前驱动实现的接口,DriverManager都是实现了这个接口的,才会认为它是一个数据库驱动,所以mysql的jar包的驱动也实现了这个接口,在文件的内部就需要写上需要暴露的接口的的实现类,比如mysql某个版本的驱动就是com.mysql.jdbc.Driver
  • 2.此时DriverManager就可以去拿到当前的实现类的类名,并且用类加载器加载,在spi机制中提供了一个类ServiceLoader,只需把想要的接口的名字传入即可,接下来会有一个加载器,这个加载器就可以使用迭代器拿到当前的类名并且创建这个对象
    ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);


依据代码调试演示DriverManager加载驱动jar包

1.基础JDBC代码

java 复制代码
public class JDBCExample {
    static final String JDBC_DROVER = "com.mysql.cj.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql:///demo1";
    static final String USER = "root";
    static final String PASS = "123456";

    public static void main(String[] args) {
        Connection coon = null;
        Statement stmt = null;
        try {
            coon = DriverManager.getConnection(DB_URL,USER,PASS);
            stmt = coon.createStatement();
            String sql = "select name,author from book";
            ResultSet r = stmt.executeQuery(sql);
            while (r.next()) {
                System.out.print("name: " + r.getString("name"));
                System.out.print("author: " + r.getString("author") + "\n");
            }
            stmt.close();
            coon.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

2. 初始化

java 复制代码
static {
    loadInitialDrivers();
    println("JDBC DriverManager initialized");
}

3. 加载所有jar包中的驱动

  • 核心代码:
java 复制代码
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;
}



问题2:SPI中是如何获取到应用程序类加载器的?

  • SPI中使用了线程上下文中保存的类加载器进行类的加载,这个类加载器一般是应用程序类加载器。

获取当前类的上下文的类加载器



相关推荐
程序猿chen6 小时前
《JVM考古现场(十六):太初奇点——从普朗克常量到宇宙弦的编译风暴》
jvm·git·后端·程序人生·金融·java-ee·量子计算
Excuse_lighttime12 小时前
JAVA阻塞队列
java·开发语言·jvm
熙客13 小时前
JVM监控
jvm
Thanwind18 小时前
关于JVM和OS中的指令重排以及JIT优化
java·jvm·jmm
快来卷java21 小时前
JVM虚拟机篇(三):JVM运行时数据区与方法区详解
java·jvm·mysql
Aphelios3801 天前
Java全栈面试宝典:线程协作与Spring Bean管理深度解析
java·开发语言·jvm·spring·面试·职场和发展
M malloc1 天前
【C++奇遇记】C++中的进阶知识(继承(一))
java·jvm·c++
摘星编程1 天前
JVM深入原理(六)(二):双亲委派机制
jvm
李小白662 天前
JavaEE初阶复习(JVM篇)
java·jvm·java-ee
我不想当小卡拉米3 天前
C++:继承+菱形虚拟继承的一箭双雕
开发语言·jvm·c++