线程上下文类加载器

我们在使用 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. fragment中文网_更新 · React Native 中文网
  2. 算法设计与分析——动态规划——最长公共子序列
  3. nginx mozilla_我发现Mozilla的私人浏览模式存在重大缺陷。
  4. axure选中后横线切换_3、开关状态切换 —— Axure实用交互
  5. RabbitMQ中BasicGet与BasicConsume的区别
  6. 使用oracle创建表问题
  7. 强悍的 Linux —— 常用 shell
  8. Unity3d发布webplayer 部署到IIS
  9. 城通网盘,千军万马,千脑网盘,119g网盘哪个适合做网赚?
  10. zigbee协议栈串口收发 From zigbee菜鸟笔记(十 二)
  11. 深度学习(Deep Learning)综述及其延伸,入门必看!
  12. 网络空间安全未来就业前景和就业方向,看着六点
  13. winrar解压器_这是一款神奇的压缩解压软件
  14. C游戏编程入门第一讲心得
  15. STM32低功耗总结——转载
  16. 2021 年 25 大 DevOps 工具(上)
  17. python学生选课_Python开发Day07(学生选课)
  18. Python遗传算法求解函数极值
  19. 用户手册 操作手册 区别
  20. Python3 识别图片验证码的步骤

热门文章

  1. PHPSTORM下安装XDEBUG
  2. Snmp学习总结系列——开篇
  3. JAVA去掉HTMl以及CSS样式
  4. 避免css中文字体在浏览器中解析成乱码
  5. 【Quartz】问题记录注意事项【四】
  6. 为什么静态成员、静态方法中不能用this和super关键字
  7. Android Studio在线安装Android SDK注意事项
  8. Everything you need to learn about engineering freelance
  9. lowerBound与upperBound
  10. 3dmax坐标系与导出fbx的坐标系