在上一次【https://www.cnblogs.com/webor2006/p/9248621.html】对线程上下文类加载器进行理论化的了解,这里回忆一下重点之处:
这里以JDBC的这种SPI场景用图来更具体的描述一下:
而根据这个理论:
很明显JDBC会去引用JDBCImpl的具体厂商的实现,而JDBC标准是由根类加载器所加载,那对于具体实现厂商的类也会用根类加载器去加载,而由于它们是处于工程中的classPath当中,很显然是没办法由根类加载器去加载的,为了解决这个问题,线程的上下文类加载器就发挥作用了,下面举一些示例代码来对它有进一步的认识:
其结果是:
第一个输出当前线程的上下文类加载器为应用类加载器,原因如之前的理论:
那思考一下:为什么默认的线程上下文类加载器就是系统类加载器呢?肯定是在某个地方给设置了,其实它是在Launcher中进行设置的,如下:
好,这个比较容易理解~~下面还有一些理论化的东东需要再说明一下:
- 线程上下文类加载器的一般使用模式(获取 - 使用 - 还原),示例如下:
其由myMethod()里面则调用了Thread.currentThread().getContextClassLoader()获取当前线程的上下文类加载器做某些事情。 - 如果一个类由类加载器A加载,那么这个类的依赖类也是由相同的类加载器加载的(如果该依赖类之前没有被加载过的话),ContextClassLoader的作用就是为破坏Java的类加载委托机制。
- 当高层提供了统一的接口让低层来实现,同时又要在高层加载(或实例化)低层的类时,就必须要通过线程上下文类加载器来帮助高层的ClassLoader找到并加载该类。
其实这个线程上下文类加载器有点像ThreadLocal,在任何需要的时候都可以通过Thread.currentThread().getContextClassLoader()来获取上下文类加载器。