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·
- 如果喜欢,快分享给你的朋友们吧 -
我们一起愉快的玩耍吧
领取专属 10元无门槛券
私享最新 技术干货