JDBC 打破双亲委派机制:

事情还要从JDBC连接数据库开始说起:
1
//加载驱动( mysql的驱动很有意思)
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/database_name", "root", "root");

在com.mysql.cj.jdbc.Driver 这个类里面有这样一个静态代码块,在类加载的时候就会执行

static {
    try {
        DriverManager.registerDriver(new Driver());
    } catch (SQLException var1) {
        throw new RuntimeException("Can't register driver!");
    }
}

手动的方式加载,最后可以吧驱动加载到DriverManager里面,最后被调用来获取连接;
4.0之前Class.forName()会使用调者的类加载器去加载ClassLoader.getClassLoader(caller)这个驱动
(也就是当前线程ApplicationClassLoader)

2
JDBC4.0之后采用的SPI的机制,让我们不需要书写Class.forName("com.mysql.cj.jdbc.Driver");这行代码同样可以产生相同的结果;
深入去看DriverManager.getConnection()就会发现最终会调用到ServiceLoader.load(Driver.class)
在这个方法里面有这么一行代码
ClassLoader cl = Thread.currentThread().getContextClassLoader(); 
获取上下文类加载器,并且将这个上下文类加载器保存在ServiceLoader实例中,并返回;
之后会执行ServiceLoader的一个迭代器(是他的一个内部类LazyClassPathLookupIterator)
loadedDrivers.iterator();
就是在这个迭代器里面实现的SPI机制,
他通过字符串拼接找到classpath的文件:META-INF/services/java.sql.Driver 这个文件
读取里面的权限定名(com.mysql.cj.jdbc.Driver);
通过Class.forName(url,true,classLoader)来加载Class
这个classLoader就是之前实例化ServiceLoader时保存的上下文来加载器;
然后得到了我们想要的Driver.class实例;

那么他哪里打破的双亲委派机制呢?
因为DriverManager是BootStracpClassLoader启动类加载器加载的,这个时候我们的mysql驱动实例
可没有在JAVA_HOME/lib/目录下,而是在classpath目录下(需要的是Application类加载器去加载)
就不能被启动类加载器加载,但是我们又需要mysql驱动(Driver实例)
去获取mysql连接,就得向下委派了(父加载器 需要子加载器去加载,而双亲委派是子加载器委派父加载器加载)
所以打破双亲委派的关键在于获取了getContextClassLoader()上下文类加载器;

有错Call 我

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值