线程上下文类加载器

我们在使用 JDBC 时,都需要加载 Driver 驱动,不知道你注意到没有,不写

Class.forName("com.mysql.jdbc.Driver")

也是可以让 com.mysql.jdbc.Driver 正确加载的,你知道是怎么做的吗?

让我们追踪一下源码:

public class DriverManager {// 注册驱动的集合private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers= new CopyOnWriteArrayList<>();// 初始化驱动static {loadInitialDrivers();println("JDBC DriverManager initialized");}
}

先不看别的,看看 DriverManager 的类加载器:

System.out.println(DriverManager.class.getClassLoader());

打印 null,表示它的类加载器是 Bootstrap ClassLoader,会到 JAVA_HOME/jre/lib 下搜索类,但JAVA_HOME/jre/lib 下显然没有 mysql-connector-java-5.1.47.jar 包,这样问题来了,在DriverManager 的静态代码块中,怎么能正确加载 com.mysql.jdbc.Driver 呢?

继续看 loadInitialDrivers() 方法:

private static void loadInitialDrivers() {String drivers;try {drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {public String run() {return System.getProperty("jdbc.drivers");}});} catch (Exception ex) {drivers = null;}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;}
}
println("DriverManager.initialize: jdbc.drivers = " + drivers);
// 2)使用 jdbc.drivers 定义的驱动名加载驱动
if (drivers == null || drivers.equals("")) {return;
}
String[] driversList = drivers.split(":");
println("number of Drivers:" + driversList.length);
for (String aDriver : driversList) {try {println("DriverManager.Initialize: loading " + aDriver);// 这里的 ClassLoader.getSystemClassLoader() 就是应用程序类加载器Class.forName(aDriver, true,ClassLoader.getSystemClassLoader());} catch (Exception ex) {println("DriverManager.Initialize: load failed: " + ex);}
}

先看 2)发现它最后是使用 Class.forName 完成类的加载和初始化,关联的是应用程序类加载器,因此可以顺利完成类加载

再看 1)它就是大名鼎鼎的 Service Provider Interface (SPI)

约定如下,在 jar 包的 META-INF/services 包下,以接口全限定名名为文件,文件内容是实现类名称

这样就可以使用

ServiceLoader<接口类型> allImpls = ServiceLoader.load(接口类型.class);
Iterator<接口类型> iter = allImpls.iterator();
while(iter.hasNext()) {iter.next();
}

来得到实现类,体现的是【面向接口编程+解耦】的思想,在下面一些框架中都运用了此思想:
    JDBC
    Servlet 初始化器
    Spring 容器
    Dubbo(对 SPI 进行了扩展)

接着看 ServiceLoader.load 方法:

public static <S> ServiceLoader<S> load(Class<S> service) {// 获取线程上下文类加载器ClassLoader cl = Thread.currentThread().getContextClassLoader();return ServiceLoader.load(service, cl);
}

线程上下文类加载器是当前线程使用的类加载器,默认就是应用程序类加载器,它内部又是由Class.forName 调用了线程上下文类加载器完成类加载,具体代码在 ServiceLoader 的内部类LazyIterator 中:

private S nextService() {if (!hasNextService())throw new NoSuchElementException();String cn = nextName;nextName = null;Class<?> c = null;try {c = Class.forName(cn, false, loader);} catch (ClassNotFoundException x) {fail(service,if (!service.isAssignableFrom(c)) {fail(service,"Provider " + cn + " not a subtype");}try {S p = service.cast(c.newInstance());providers.put(cn, p);return p;} catch (Throwable x) {fail(service,"Provider " + cn + " could not be instantiated",x);}throw new Error(); // This cannot happen}
}

类加载器-线程上下文相关推荐

  1. java 上下文加载器_【深入理解Java虚拟机 】线程的上下文类加载器

    线程上下文类加载器 线程上下文类加载器( Thread Context ClassLoader) 是从JDK1.2 引入的,类Thread 的getContextClassLoader() 与 set ...

  2. 深入探讨 Java 类加载器

    深入探讨 Java 类加载器 类加载器(class loader)是 Java™中的一个很重要的概念.类加载器负责加载 Java 类的字节代码到 Java 虚拟机中.本文首先详细介绍了 Java 类加 ...

  3. 深入探讨 Java 类加载器(一)

    2019独角兽企业重金招聘Python工程师标准>>> 类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一.它使得 Java 类可以被动态加载到 Java ...

  4. 对象创建过程之二(类加载器)

    2019独角兽企业重金招聘Python工程师标准>>> JAVA为我们提供了两种动态加载机制. 第一种是隐式机制.其实new一个对象和调用类的静态方法时,就是隐式机制在工作. 第二种 ...

  5. 细说JVM(类加载器)

    一.类加载器的基本概念 顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中.一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java ...

  6. 深入理解Java类加载器:Java类加载原理解析

    http://blog.csdn.net/zhoudaxia/article/details/35824249 1 基本信息 每个开发人员对java.lang.ClassNotFoundExcetpi ...

  7. Android插件基础之类加载器学习

    记录学习java 加载器学习所获心得,逐步记录了解java加载器的过程.为了知悉android 插件化的实现原理,从而需要从头了解android加载apk,以及基础的java类加载的加载过程情况,为方 ...

  8. 深入理解JVM(1):类加载器

    文章目录 一.类加载简介 1.简介 2.Java虚拟机与程序的生命周期 3.类的加载.连接与初始化(类加载的最重要的3个阶段) 3.1加载 3.2连接 3.3 初始化 4.类的使用和卸载(类加载的剩余 ...

  9. 利用classloader同一个项目中加载另一个同名的类_线程上下文类加载器ContextClassLoader内存泄漏隐患...

    前提 今天(2020-01-18)在编写Netty相关代码的时候,从Netty源码中的ThreadDeathWatcher和GlobalEventExecutor追溯到两个和线程上下文类加载器Cont ...

最新文章

  1. jmeter怎么在服务器上运行,如何通过jenkins在远程服务器上运行jmeter测试
  2. 如何进行MaxCompute 用户认证?
  3. day30,网络编程和各种协议
  4. .html文件可以删掉吗,packages文件夹可以删除吗?
  5. js弹出框、对话框、提示框、弹窗总结
  6. windows便签快捷键_超级实用的Windows快捷键
  7. K线技术指标实现详解—MA
  8. Activity跳转并传递
  9. 域名系统几类服务器,域名服务器可分为什么类型
  10. Django电商网站项目(7)-部署与总结
  11. mysql 数据库 back_log 参数
  12. 集合类 Java中的集合类解析和一些有深入的面试题
  13. 【编程实践】快速构建软件:从“快速移动并打破事物”到“快速移动,并保持稳定”
  14. 建立蜜蜂需求模型过程中参考的网站:
  15. 盘点激光雷达常用的10大数据处理软件
  16. OSChina 周二乱弹 —— 你醒啦?现在你已经是丧尸了
  17. scrapy保存图片、音频
  18. 前端不使用 i18n,如何优雅的实现多语言?
  19. 服务器上搭建teamspeak3
  20. 一阶广义差分模型_向后差分公式法、广义 α 法和龙格-库塔法

热门文章

  1. 设计模式(十)——抽象工厂模式
  2. JNI基础 c语言调用java方法
  3. Flappy bird需求规格说明书
  4. Java内存管理:深入Java内存区域
  5. CYQ.Data 轻量数据层之路 使用篇-MAction 取值赋值 视频[带音乐] F (二十四)
  6. Qtum量子链帅初受邀火星特训营面对面授课
  7. 华为FusionCube从融合到超融合 只为让计算变简单
  8. Collections练习之按照字符串长度进行排序
  9. 路由器扫描的Java源码
  10. Mysql 主从复制常用管理任务介绍