源码分析Tomcat的类加载机制

No.1 初始化

在前面的文章中,我们已经详细介绍了tomcat的启动过程(init阶段和start阶段)。

我们在init阶段中完成了tomcat类加载器初始化,具体过程我们来回顾一下代码:

shared.loader和server.loader为空,所以直接返回parent,即catalina与shared类加载器的父类加载器为common类加载器

common.loader=$/lib,$/lib/*.jar,$/lib,$/lib/*.jar,所以ClassLoaderFactory.createClassLoader静态方法:

在createClassLoader中指定参数parent==null时,最终会以系统类加载器(AppClassLoader)作为父类加载器,这解释了为什么commonClassLoader的父类加载器是AppClassLoader.

小结:

catalinaLoader = sharedLoader = commonLoader = URLClassLoader

catalinaLoader、sharedLoader、commonLoader的父类加载器是AppClassLoader

第一步:获取ParentClassLoader,主要看getParentClassLoader()方法,具体代码如下:

也就是ContainerBase.getParentClassLoader(),即ContainerBase.parentClassLoader属性,它是在ContainerBase.setParentClassLoader()方法中设置的。

ContainerBase.setParentClassLoader()方法是在org.apache.catalina.startup.SetParentClassLoaderRule.begin()方法中调用的,即SetParentClassLoaderRule.parentClassLoader属性

SetParentClassLoaderRule.parentClassLoader是在Catalina.createStartDigester()方法被设置的,即就是org.apache.catalina.startup.Catalina.parentClassLoader属性的值。

也就是在org.apache.catalina.startup.Bootstrap.init() 方法中通过反射设置的,也就是Catalina.parentClassLoader = sharedLoader。

小结:WebClassLoader的父类加载器是Shared ClassLoader

第二步:启动WebappLoader,主要是WebappLoader.startInternal()方法,即通过WebappLoader.createClassLoader() 来创建类加载器,并且设置其资源路径为当前Webapp下某个context的类资源。

loaderClass的值是字符串org.apache.catalina.loader.WebappClassLoader,通过反射来实例化WebappClassLoader。由于每个Webapp下的类资源由不同的WebappClassLoader负责加载,因此Webapp下各个Context的类资源是独立的。

No.2 tomcat类加载逻辑2.1、加载tomcat容器本身的类资源

具体来看看securityClassLoad:

这里使用的catalinaLoader来加载tomcat容器所需的类:

Tomcat核心class,即org.apache.catalina.core路径下的class;

org.apache.catalina.loader下的ResourceEntry和WebappClassLoader$PrivilegedFindResourceByName;

Tomcat有关session的class,即org.apache.catalina.session路径下的class;

Tomcat工具类的class,即org.apache.catalina.util路径下的class;

javax.servlet.http.Cookie;

Tomcat处理请求的class,即org.apache.catalina.connector路径下的class;

Tomcat其它工具类的class,也是org.apache.catalina.util路径下的class;

2.2、WebappClassLoader的类加载机制

WebappClassLoader 是每个web项目对应一个WebappClassLoader。这样做的目的是每个项目中都会有相同的类(package+classname),而类的内容不一样。这样每个项目一个WebappClassLoader可以达到隔绝项目类冲突的问题。

WebappClassLoader继承自WebappClassLoaderBase,所以来看看WebappClassLoaderBase.loadClass()方法:

第一步:在本地缓存中查找是否已经加载过该类:调用findLoaderClass0() 方法检查WebappClassLoader中是否加载过此类。

再调用findLoadedClass()方法检查是否加载过该类。

第二步:调用j2seClassLoader.loadClass()让系统类加载器(AppClassLoader)尝试加载该类,主要是为了防止一些基础类会被web中的类覆盖,如果加载到即返回,返回继续。

第三方:调用filter()方法检查该类是否在指定的包名下,如果在则委托父类加载器(StandardClassLoader)去加载。

第四步:调用findClass(),使用web应用的类加载器将自行加载。

第五步:到此还没有加载成功,则委托父类加载器(StandardClassLoader)去加载。

WebappClassLoader的类加载过程中,第四第五步的顺序违反了双亲委托机制。

No.3 总结

用一张图类总结一下tomcat的类加载机制:

·end·

- 如果喜欢,快分享给你的朋友们吧 -

我们一起愉快的玩耍吧

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

扫码关注云+社区

领取腾讯云代金券