Quantcast
Channel: CSDN博客推荐文章
Viewing all articles
Browse latest Browse all 35570

Tomcat类加载器(附JVM类加载器简介)

$
0
0

Tomcat类加载器(附JVM类加载器简介)

         学习tomcat类加载器,首先得先看下JVM提供了几种类加载器,毕竟tomcat类加载器是依赖于JVM类加载器的。

         JVM类加载器:引导类加载器(bootstrapclassloader)、扩展类加载器(extension classloader)、系统类加载器(又称应用类加载器,system classloader)。引导类加载器是扩展类加载器的父加载器,而扩展类加载器又是系统类加载器的父加载器。

(1) Bootstrap Classloader 是JVM 利用JNI的方式采用c语言实现的(即它并不是java.lang.ClassLoader的子类)。负责加载%JAVA_HOME%\lib下的类库或者是由-Xbootclasspath选项或使用-D选项指定sun.boot.class.path系统属性指定的类。

(2) Extension ClassLoader 由sun.misc.Launcher$ExtClassLoader实现,负责加载%JAVA_HOME%\jre\lib\ext中的类库或者是由系统变量java.ext.dirs指定的类库。

(3) System ClassLoader 由sum.misc.Launcher$AppClassLoader实现,负责加载java应用涉及到的类。加载器可以通过ClassLoader.getSystemClassLoader()来获取。如图所示:


从图中的第二个红框,我们也可以看出System Classloader是sun.misc.Launcher的一个内部类。其实扩展类加载器也是sun.misc.Launcher的一个内部类。

在看一下这个神秘的Launcher类吧,打开rt.jar源码(找这个源码费劲,还是用泼墨大神推荐的jd-gui.exe直接打开吧!)找到sun.misc.Launcher 看下系统类加载器的定义:

 扩展类加载器的定义:


以上两个截图是系统类加载器和扩展类加载器的定义。其中从两个类定义的红框中可以看出,系统类加载器加载系统属性java.class.path指定目录的类库,而扩展类加载器加载系统属性java.ext.dirs指定目录的类库。具体这两个系统属性的值是什么呢?实验一把才知道:


我本机实验结果如上图。出乎我的意料的是为什么 系统变量java.ext.dirs指定的路径会有一个 c:\windows\sun\java\lib\ext 我本机都没有这个目录,这个问题抛出来,谁知道为什么可以告诉我。

上面是JVM类加载器的一些基本知识,再来总结一下类加载器的委派模型。bootstrap classloader 是extension classloader的父加载器,而extension classloader是 system classloader的父加载器。在具体加载的时候遵循这么一个模型:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父加载器去完成。所有的加载请求最终都会传递到顶层的引导类加载器,只有父类加载器不能加载这个类的时候才将权限下放交由子类加载器来完成类加载。


附图一个:

Ps:开发人员在构建自己的类加载器的时候,依然遵循这个外派模型,自己定义的类加载器要以system classloader作为父类加载器。至于为什么这么做,是出于安全考虑.

 

Tomcat类加载器:         关于JVM类加载器就先总结这么多.回过头来再来看看tomcat的类加载器。之前研究过tomcat在启动过程会初始化三个类加载器,commonLoader,catalinaLoader,sharedLoader(在tomcat5以后catalinaLoader和sharedLoader默认不启用),那就研究一下commonLoader的初始化过程:


这个初始化函数可以看出在构造commonLoader的时候将系统类加载器作为了其父类加载器,createClassLoader的第二个参数就是在设置父类加载器的值。断点进入验证一下便知:

图中红框显示的是parent的值,其值就是上文提到的JVM的系统类加载器sun.misc.Launcher的内部类AppClassLoader的实例。

   通过调试也可以看出给commonLoader赋予的值是org.apache.catalina.loader.StandardClassLoader,详情如下图:

 

  小结一下:在tomcat的启动过程中commonLoader被赋予的值是tomcat自定义的org.apache.catalina.loader.StandardClassLoader类加载器。其父类加载器是JVM的系统类加载器AppClassLoader.

  上文是回顾以前研究tomcat启动过程涉及到的类加载器的东西。现在再宏观的看一下tomcat的类加载器。Tomcat的类加载器涉及到的类在org.apache.catalina.loader这个包下(如图):

 

tomcat一共定义了两种类加载器,一种是上文提到的StandardClassLoader、另一种是用来加载web应用的WebappClassLoader。StandardClassLoader用以实例化commonloader、catalinaLoader、sharedLoader。它不提供热部署功能。而WebappClassLoader专门用来加载web程序的,提供热部署功能即发生calssLoader搜索路径下的资源改变后,服务器重新加载。

  另外看到这个目录下还涉及到两个长得很像类加载器的类:WebappLoader和VirtualWebappLoader。WebappLoader我的理解是应用加载器而不是类加载器,它依赖了WebappClassLoader来完成类的加载,并对热部署、生命周期控制等功能做了一些控制,是对WebappClassLoader的一层封装,这个加载器和context级的容器相关联。而VirtualWebappLoader是WebappLoader的子类。瞄一眼注释:

从注释中可以看出,这个主要是和conf/context.xml这个文件相关联,主要功能是加载context.xml配置文件中设置的一些java类库,由于WebappClassLoader只能加载WEB-INF/class和WEB-INF/lib下的类库。而想扩展一下加载路径又不想添加到WEB-INF/lib中的时候,可以配置在context.xml文件中。具体的配置方式注释里也列出了DEMO就不纠结这个了。

  Ps:这里补充一点就是这个context.xml和server.xml的关系,在tomcat6以后的版本中,context元素从server.xml文件中独立出来了,并放在了context.xml配置文件中。因为server.xml是不可动态加载的资源,服务器一旦启动了之后,要修改这个文件,就得重启服务器才能重新加载。而context.xml文件则不然,tomcat服务器会定时扫描这个文件。一旦发现文件被修改了(时间戳变了),就会重新加载这个文件,而不需要重启服务器。

  附一张应用加载器和类加载器的类关联图:

 

 

  再结合这个图总结一下吧,应用加载器webappLoader实现了org.apache.catalina.Reloader接口,所以能进行动态重载.Reloader接口定义了类重载的一些方法。WebappClassLoader继承了java.net.URLClassLoader类。实现重载的方式是在后台起一条线程定时的去check资源目录下class文件的修改时间戳,如果有更新就reload。具体的源代码有时间自定类类加载器的时候在研究总结!

  

作者:lantian0802 发表于2013-4-13 17:56:22 原文链接
阅读:0 评论:0 查看评论

Viewing all articles
Browse latest Browse all 35570

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>