类加载器详解以及JSP的hotSwap

类加载器:
在类加载的第一步'加载'过程中,首先就是通过类的全限定名去获取类的二进制字节流,这个步骤就是由类加载器来完成的,每个类加载器在虚拟机中都有其唯一的类名称空间,不同的类加载器位于不同的名称空间中,在虚拟机中,如果想唯一确定一个类,除了类的全限定名外还需要加载该类的加载器。所以即使是同一个类,被不同的加载器加载,也必然不相等
java中一共有三种类加载器,分别是:
启动类加载器bootStrap ClassLoader :负责加载java_home/lib目录下的核心类库,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机内存中。
扩展类加载器 :负责加载java_home/lib/ext目录下的、或者被java.ext.dirs参数指定的路径中的所有类库
系统类加载器 :负责加载用户路径classPath上的所有类库,ClassLoader.getSystemClassLoader()就可以直接返回系统类加载器,如果我们想自定义类加载器,直接继承系统类加载器即可
扩展类加载器和系统类加载器都可以在程序中直接使用,启动类加载器不可以直接使用,但类的加载最终可以委派给它,下面我们就介绍家在过程中到底是如何委派的
             加载器的双亲委派机制:
在类加载器加载类时,并不是直接去生成类的二进制字节码,而是会将这个动作委托给父加载器进行加载,而父加载器也会如此,前面介绍的三种加载器以及自定义加载器,除了启动类加载器没有父加载器外,其他加载器都有自己的父加载器,父子关系也就是上文介绍的顺序,越往上级别越高。所以正常情况下,所有的加载请求最终都会被委托到启动类加载器来执行,除非父加载器反馈自己无法加载,子加载器才会去执行加载操作。
为什么要用这种机制来进行加载呢,试想一下如果每个加载器都是自行加载,你自己定义一个java.lang.Object类,然后再自定义一个来加载器加载你写的这个Object类,那就会同时存在多个Object类,会严重影响虚拟机安全稳定的运行。

web服务器中的类加载器:
主流的web服务器都实现了自己的类加载器,因为都要解决如下几个问题:
启动多个java服务时,服务之间引用的jar包被加载到虚拟机后可以互不干扰,包括多个java服务都依赖了同一个jar包,也不会产生冲突
多个java服务可以共享需要共享的jar包
支持JSP的服务器,一般都要实现hotSwap功能,也就是修改后无需重启自动重部署的功能
基于以上原因,如果只用一个classPath来对所有的类进行加载肯定是不行的,所以一般web服务器都会有多个自定义的类加载器分别负责不同classPath下的类加载,比如Tomcat的lib目录下的jar包由一个CommonClassLoader负责加载,而webApps目录中各个项目的WEB-INFO目录下的jar包由WebAppClassLoader加载器加载,CommonClassLoader是WebAppClassLoader的父类加载器,其加载的类可以被WebAppClassLoader加载的类共享,而tomcat会为每个web应用分配一个WebAppClassLoader实例,这些实例加载的类之间互相隔离;对于JSP文件,tomcat会为每个JSP分配一个JspClassLoader实例,当JSP文件发生变化时,原来的加载器实例就会被废弃,tomcat会重新创建加载器实例对该文件重新加载,从而实现热替换

猜你喜欢

转载自blog.csdn.net/wb_snail/article/details/80608542