破坏双亲委派机制及SPI源码解析

双亲委派机制的目的是防止类的重复加载,使类加载具有优先级的层次关系,但是这种机制有时候会有弊端:
因为类加载有一条机制:当被装载的类引用了另外一个类的时候,虚拟机就会使用装载第一个类的类装载器装载被引用的类, 设想在这种情况下java.sql.DriverManager是由BootStrapClassLoader加载的,那么也会用BootStraoClassLoader去加载com.mysql.cj.jdbc.Driver(假如当前驱动是Mysql),而第三方依赖原则上来说是应该由AppClassLoader来加载的,用BootStrapClassLoader就会加载不到,解决办法是引入了SPI(ServiceLoader)的机制,下面附上源码

java.sql.DriverManager#loadInitialDrivers
在这里插入图片描述
在这里插入图片描述
这里先调用load返回一个ServiceLoader,然后获取到iterator调用next,其实这里的iterator就是ServiceLoader.LazyIterator

java.util.ServiceLoader.LazyIterator#next
在这里插入图片描述
这里调用了nextService()方法:可以看到加载了nextName,而这个nextName是什么呢? 其实就是mysql-connector-java/META-INF/services/java.sql.Driver中的配置的内容:com.mysql.cj.jdbc.Driver,使用迭代器是因为看这个文件中可以配置多个Driver的实现类在这里插入图片描述
在这里插入图片描述
hasNextService():fullName就是在META-INF/services/目录下的文件名
在这里插入图片描述
而类加载器是怎样加载到我们项目目录下的这个实现类呢? 再回到最开始的loadInitialDrivers方法,里面调用的erviceLoader.load(Driver.class)方法:
在这里插入图片描述
ClassLoader cl = Thread.currentThread().getContextClassLoader(); 这句代码就是获取到了线程上下文类加载器,也就是用这个加载器来加载java.sql.Driver和各数据库厂商的实现类, 而这个线程上下文类加载器默认情况下就是AppClassLoader

总结
BootStrapClassLoader加载DriverManager,却通过线程上下文类加载器来加载com.mysql.cj.jdbc.Driver,这是一种父类加载器去请求子类加载器完成类加载的行为,实际上是打破了双亲委派模型的层次结构来逆向使用类加载器,已经违背了双亲委派模型的一般性原则, 但也是无可奈何的事情

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值