设为首页 收藏本站
查看: 561|回复: 0

[经验分享] tomcat源码阅读一--------ClassLoader

[复制链接]

尚未签到

发表于 2017-1-23 07:28:01 | 显示全部楼层 |阅读模式
阅读tomcat的源码之前有一些预备知识必须掌握,比如ClassLoader,因为我在看tomcat源码的入口类org.apache.catalina.startup.Bootstrap时,基本就是ClassLoaderFactory.createClassLoader(repositories, classLoader)在加载repositories中的*******.jar
 
 
tomcat启动过程中的类加载器层次结构图:

DSC0000.jpg
  

1 Java核心classloader
bootstrap
bootstrap classloader是由JVM启动的,用于加载%JAVA_HOME%/jre/lib/下的JAVA平台自身的类(比如rt.jar中的类等)。这个classloader位于JAVA类加载器链的顶端,是用C/C++开发的,而且JAVA应用中没有任何途径可以获取到这个实例,它是JDK实现的一部分 
 
extension
entension classloader用于加载%JAVA_HOME%/jre/lib/ext/下的类,它的实现类是sun.misc.Launcher$ExtClassLoader,是一个内部类 
 
2  system
System类加载器,也叫App类加载器,一般情况下,对于普通的JAVA应用,ClassLoader体系就到system为止了。平时编程时,甚至都不会感受到classloader的存在,但是对于其他一些应用,比如web server,插件加载器等,就必须和ClassLoader打交道了。这时候默认的类加载器不能满足需求了(类隔离、运行时加载等需求),需要自定义类加载器,并挂载到ClassLoader链中(默认会挂载到system classloader下面) 
在tomcat里,默认情况下(通过setclasspath.sh修改CLASSPATH的值,而忽略环境变量中的CLASSPATH,会加载%CATALINA_HOME%/bin目录下的bootstrap.jar、tomcat-juli.jar、commons-daemon.jar ,此时tomcat就相关于一个App
 
3  Common 
这个类加载器是tomcat特有的,对于所有web app可见。这个类加载器默认会加载%CATALINA_HOME%/lib下的所有jar包,这些都是tomcat的核心
 
4  WebappX 
对于部署在容器中的每一个webapp,都有一个独立的ClassLoader,在这里实现了不同应用的类隔离 
这里加载的就是我们熟悉的/WEB-INF/classes 和 /WEB-INF/lib下的jar
 
 
一般情况下ClassLoader是采用双亲委托模型加载类的,过程如下:
  查找类所在位置,并将找到的Java类的字节码装入内存,生成对应的Class对象。Java的类装载器专门用来实现这样的过程,JVM并不止有一个类装载器,事实上,如果你愿意的话,你可以让JVM拥有无数个类装载器,当然这除了测试JVM外,我想不出还有其他的用途。
  其实类装载器自身也是一个类,它也需要被装载到内存中来,那么这些类装载器由谁来装载呢,总得有个根吧?没错,确实存在这样的根,它就是神龙见首不见尾的Bootstrap ClassLoader. 为什么说它神龙见首不见尾呢,因为根本无法在Java代码中抓住哪怕是它的一点点的尾巴,尽管你能时时刻刻体会到它的存在,因为java的运行环境所需要的所有类库,都由它来装载,而它本身是C++写的程序,可以独立运行,可以说是JVM的运行起点。
  在Bootstrap完成它的任务后,接着还会使用扩展类装载器ExtClassLoader,它用于装载Java运行环境扩展包中的类,然后会生成一个AppClassLoader,AppClassLoader可以通过调用ClassLoader.getSystemClassLoader() 来获得,假定程序中没有使用类装载器相关操作设定或者自定义新的类装载器,那么我们编写的所有java类通通会由它来装载。AppClassLoader查找类的区域就是耳熟能详的Classpath,按照它的类查找范围给它取名为类路径类装载器。
  还是先前假定的情况,当Java中出现新的类,AppClassLoader首先在类传递给它的父类类装载器,也就是Extion ClassLoader,询问它是否能够装载该类,如果能,那AppClassLoader就不干这活了,同样Extion ClassLoader在装载时,也会先问问它的父类装载器。我们可以看出类装载器实际上是一个树状的结构图,每个类装载器有自己的父亲,类装载器在装载类时,总是先让自己的父类装载器装载,如果父类装载器无法装载该类时,自己就会动手装载,如果它也装载不了,就抛Exception,class not found。
  当由直接使用类路径装载器装载类失败抛出的是NoClassDefFoundException异常。如果使用自定义的类装载器loadClass方法或者ClassLoader的findSystemClass方法装载类,如果你不去刻意改变,那么抛出的是ClassNotFoundException。(用过spring的朋友,配错类路径时肯定碰到过这个提示)
   
  值得一提jdk官方文档里对getClassLoader()的描述中指出:
  如果一个类是通过bootstrap 载入的,那我们通过这个类去获得classloader的话,有些jdk的实现是会返回一个null的,比如说我用 new Object().getClass().getClassLoader()的话,会返回一个null,这样的话上面的代码就会出现NullPointer异常.所以保险起见是使用我们自己写的类来获取classloader,"this.getClass().getClassLoader()“,这样一来就不会有问题。
 
tomcat的ClassLoader与标准的ClassLoader委托模型不同,在启动的时候的加载顺序为
  Bootstrap--->System--->/WEB-INF/classes---> /WEB-INF/lib/*.jar---> Common
 
当webappLoader需要加载一个类的时候,首先是委托Bootstrap;然后尝试自行加载;接着是system;最后才会委托Common 
from the perspective of a web application, class or resource loading looks in the following repositories, in this order:

  • Bootstrap classes of your JVM
  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/*.jar of your web application
  • System class loader classes 
  • Common class loader classes 
  但如果在web.xml里配置了<Loader delegate="true"/>
  委托顺序就会变成Bootstrap--》system--》Common--》尝试自行加载

  • Bootstrap classes of your JVM
  • System class loader classes 
  • Common class loader classes
  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/*.jar of your web application
 
 
到目前为止,我还没搞明白为什么把Common放在最后,而不按正常的双亲委托模型来弄-.-!
 
tomcat官网有描述:
  http://tomcat.apache.org/tomcat-8.0-doc/class-loader-howto.html
 
 

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-332148-1-1.html 上篇帖子: tomcat OutOfMemory 解决办法 下篇帖子: Eclipse配置Tomcat的方法[图解]
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表