学习
实践
活动
工具
TVP
写文章

理解TCCL:线程上下文类加载器

蹲厕所的熊 转载请注明原创出处,谢谢!

前言

相信有一定基础的同学对类加载器(ClassLoader)以及类加载机制不会陌生,如果你还不了解什么是类加载器,双亲委派模型是什么的话,先

戳我

去学习~

在看JDK、Tomcat以及Spring源码的时候,会经常的出来 这句代码,一开始我也似懂非懂的理解,但是还是不知道它的使用场景是什么,总结起来有以下几个问题:

Thread.getContextClassLoader()获取到的classLoader和getClass().getClassLoader()的有什么区别?

什么场景下会用到Thread.getContextClassLoader()的方式获取classLoader?

下面我们会从JDK的SPI机制、Tomcat以及Spring三个方面去剖析。

SPI加载问题

之前我写过一篇SPI机制的文章,其中ServiceLoader的load方法是获取到了TCCL来加载用户的类的,那么有同学想过是为什么吗?

Java提供了很多SPI,允许第三方为这些接口提供实现,最常见的SPI实现有JDBC、JNDI等等,根据类加载器的双亲委派模型,加载ServiceLoader的 是不能加载SPI的实现类的,因为SPI的实现类是由 加载的,而 是不能委派 来加载类的,那该怎么办呢?

线程上下文类加载器正好解决了这个问题,默认情况下,Java应用的线程上下文类加载器默认是AppClassLoader,这样ServiceLoader就可以成功加载SPI的实现类了。

Tomcat与Spring的加载问题

Tomcat基本遵守了JVM的委派模型,但也在自定义的类加载器中做了细微的调整,以适应Tomcat自身的要求。下面是一张Tomcat的类加载体系图:

CommonClassLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问。

CatalinaClassLoader:Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见。

SharedClassLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见。

WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见。

稍微做一下小结:CommonClassLoader 能加载的类都可以被 CatalinaClassLoader 和 SharedClassLoader 使用,而 CatalinaClassLoader 和 SharedClassLoader 自己能加载的类则与对方相互隔离。WebAppClassLoader 可以使用 SharedClassLoader 加载到的类,但各个 WebAppClassLoader 实例之间相互隔离。

这时有的同学要问了,如果有10个web应用程序都用到了Spring的话,可以把Spring的jar包放到common或者shared目录下让这些程序共享。Spring 的作用是管理每个web应用程序的bean,getBean时自然要能访问到应用程序的类,而用户的程序显然是放在 /WebApp/WEB-INF 目录中的(由 WebAppClassLoader 加载),那么在 CommonClassLoader 或 SharedClassLoader 中的 Spring 容器如何去加载并不在其加载范围的用户程序(/WebApp/WEB-INF/)中的Class呢?

原来spring根本不会去管自己被放在哪里,它统统使用TCCL来加载类,而TCCL默认设置为了WebAppClassLoader,也就是说哪个WebApp应用调用了spring,spring就去取该应用自己的WebAppClassLoader来加载bean,简直完美~

有兴趣的可以接着看看具体实现。在web.xml中定义的listener为 ,它最终调用了 类来装载bean,具体方法如下(删去了部分不相关内容):

总结

通过前面结合SPI、Tomcat以及Spring中TCCL的应用场景,相信前面提的那两个问题就都容易解决了。最后,我们总结一下线程上下文类加载器的适用场景:

1.当高层提供了统一接口让低层去实现,同时又要是在高层加载(或实例化)低层的类时,必须通过线程上下文类加载器来帮助高层的ClassLoader找到并加载该类。

2.当使用本类托管类加载,然而加载本类的ClassLoader未知时,为了隔离不同的调用者,可以取调用者各自的线程上下文类加载器代为托管。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180712G09UNI00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码关注腾讯云开发者

领取腾讯云代金券