freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Tomcat类加载器
2023-10-14 02:54:46

前言

写这篇文章的目的主要是在分析shiro反序列化的时候遇到了tomcat加载不了transform数组的问题,于是把tomcat涉及到的几个类加载器都研究了一下,写个文章总结一下,如有问题欢迎师傅指出。

Tomcat为什么要实现这么多类加载器?

Tomcat是个容器,一个web容器可能需要部署两个应用程序,不同的应用会依赖不同的第三方库的不同版本,因此要求有些类库需要隔离,有些类库需要共享。

Tomcat类加载器

按照设计图并结合源码来分析:

image

Common类加载器

Tomcat最基本的类加载器,默认是加载$CATALINE_HOME/lib 下的jar 包

我来看看源码:

首先commonLoaderBootstrap中初始化,调用createClassLoader来创建,之后会作为catalinaLoadersharedLoader的父加载器

image

其中会调用CatalinaProperties.getProperty获取要加载的路径,property对应配置文件catalina.properties或虚拟启动时参数赋值,之后就是些扫描path中的jar包和类。

image

catalina类加载器

Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见,听名字像是Catalina类的加载器,但不完全是

我来看看源码:

Bootstrap中初始化,调用createClassLoader来创建,以commonLoader作为父加载器

image

调用CatalinaProperties.getProperty,默认为空,所以直接使用父加载器

image

之后用catalinaLoader去加载并实例化org.apache.catalina.startup.Catalina

image

之后又通过反射将ParentClassLoader改成了sharedLoader

image

所以调用WepAppClassLoader来加载时使用的parent其实是sharedLoader

shared类加载器

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

来看看源码:

Bootstrap中初始化,调用createClassLoader来创建,以commonLoader作为父加载器

image

调用CatalinaProperties.getProperty,默认为空,所以直接使用父加载器

image

之后就是通过反射将Catalina.parentClassLoader设置为sharedLoader

image

Webapp类加载器

各个Webapp私有的类加载器,加载我们web应用中,"WEB-INF/libs" 和"WEB-INF/classes" 这个目录下的jar

来看看源码:

初始化在StandardContext.startInternalWebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader实例之间相互隔离

image

具体加载器是通过实例化WebappClassLoaderBase

image

JasperLoader

每个jsp文件都由一个JasperLoader去加载,JasperLoader的加载范围仅仅是这个JSP文件所编译出来的那一个Class,它出现的目的就是为了被丢弃:当服务器检测到JSP文件被修改时,会替换掉目前的JasperLoader的实例,并通过再建立一个新的Jsp类加载器来实现JSP文件的热部署功能。

这里不详细的去研究

tomcat的类加载机制

我们知道,tomcat的类加载机制是违反了双亲委托原则的,具体是怎么实现的

直接看源码:

来到WebappClassLoaderBase#loadClass(java.lang.String, boolean),首先调用findLoadedClass0,先从缓存中获取有无加载过的class

image
image

判断有无开启双亲委派机制,有的话会先委派父加载器去加载

image

使用WebApp类加载器去加载,其逻辑是扫描"WEB-INF/libs"和"WEB-INF/classes"目录下jar包中有无对应name的class类,有的话就返回,具体扫描的逻辑是用jarFile类实现的,有兴趣的师傅可以去跟下。

image

这时我们的[Lorg.apache.commons.collections.Transformer;这个类名是肯定扫描不到的,而org.apache.commons.collections.Transformer类名是可以扫描到的

image

image

后面判断没有开启双亲委派的话,会用commonloader去加载类,也就是$CATALINE_HOME/lib目录下的。

image

[Lorg.apache.commons.collections.Transformer;肯定是加载不到的,而[Ljava.lang.StackTraceElement;就可以加载到

image

image

最后所有加载器都加载不到的话,就抛出ClassNotFoundException的异常

image

所以网上很多说加载不了数组的结论是错的,准确来说可以加载共享库中的对象数组但不能加载自定义类和第三方类的对象数组

总结

tomcat的类加载机制是违反了双亲委托原则的,对于一些未加载的非基础类(Object,String等),各个web应用自己的类加载器(WebAppClassLoader)会优先加载,加载不到时再交给commonClassLoader走双亲委托。所以也不会导致核心api被篡改的问题。

# web安全 # java # tomcat # Java类加载器
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录