3:类加载机制深度解析(Tomcat打破双亲委派机制)(文末有项目连接)

1:Tomcat的类加载机制
以Tomcat类加载为例,Tomcat 如果使用默认的双亲委派类加载机制行不行?
我们思考一下:Tomcat是个web容器, 那么它要解决什么问题:

 1: 部署在同一个web容器中相同的类库相同的版本可以共享。
    否则,如果服务器有10个应用程序,那么要有10份相同的类库加载进虚拟机。
    
2:一个web容器(Tomcat)可能需要部署两个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本
    不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。
3:web容器(Tomcat)也有自己依赖的类库,不能与应用程序的类库混淆。基于安全考虑,
应该让容器的类库和程序的类库隔离开来。

4:web容器(Tomcat)要支持jsp的修改,我们知道,jsp 文件最终也是要编译成class文件才能在虚拟机中运行,
    但程序运行后修改jsp已经是司空见惯的事情, web容器需要支持 jsp 修改后不用重启。

回到问题:
问题 1 :默认的类加载器是能够实现的,因为他的职责就是保证唯一性。

问题 2 和 问题3 :如果使用默认的类加载器机制,那么是无法加载两个相同类库的不同版本的,
                    默认的类加器是不管你是什么版本的,只在乎你的全限定类名,并且只有一份。
问题 4:我们要怎么实现jsp文件的热加载,jsp 文件其实也就是class文件,那么如果修改了,但类名还是一样,
          类加载器会直接取方法区中已经存在的,修改后的jsp是不会重新加载的。
          那么怎么办呢?
          每个jsp文件对应一个唯一的类加载器,当一个jsp文件修改了,定时任务检查到了,
          就直接卸载这个jsp类加载器。重新创建类加载器,重新加载jsp文件。
2:Tomcat的类加载机制流程图
tomcat的几个主要类加载器:
commonLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;

catalinaLoader:Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;

sharedLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;
WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见,
                            比如加载war包里相关的类,每个war包应用都有自己的WebappClassLoader,
                            实现相互隔离,比如不同war包应用引入了不同的spring版本,这样实现就能加载各自的spring版本;

关系:
 commonLoader (最基本的类加载器 实现了公有类库的共用)包含  catalinaLoader 与 sharedLoader  (解决问题1)
 
 catalinaLoader(Tomcat私有加载器  只能加载Tomcat私有的类 )(解决问题3)
与  sharedLoader(共享Webapp加载器) 相互隔离 
 
 sharedLoader (共享Webapp加载器) (可以加载多个WebappClassLoader) 
与  catalinaLoader(Tomcat私有加载器) 相互隔离 
 
WebappClassLoader(单独应用 只能加载本WebappClassLoader下的类)  (解决问题2)(解决问题4)
与 WebappClassLoader(单独应用)相互隔离  
3:Tomcat的类加载机制总结
Tomcat 这种类加载机制违背了java 推荐的双亲委派模型
tomcat 为了实现隔离性:
    1:每个webappClassLoader加载自己的目录下的class文件,不会传递给父类加载器,打破了双亲委:派机制。
    2:web容器(Tomcat)自己依赖的类库 与 其他 Wep应用程序的类库  隔离;
4:代码实战
参考自定义实现打破双亲委派机制即可

特别注意:同一个JVM内,两个相同包名和类名的类对象可以共存,因为他们的类加载器可以不一样,
            所以看两个类对象是否是同一个,除了看类的包名和类名是否都相同之外,还需要他们的类加载器也是同一个才能认为他们是同一个。
//利用 获取路径 模拟分别是从两个wep包下加载 同类名的类

//创建类加载器1
MyClassLoader classLoader1 = new MyClassLoader("D:/test1");
 Class clazz1 = classLoader1.loadClass("com.example.demo.classLoader.User");

//创建类加载器1
MyClassLoader classLoader2 = new MyClassLoader("D:/test2");
 Class clazz2 = classLoader2.loadClass("com.example.demo.classLoader.User");


System.out.println(clazz1.getClassLoader());
System.out.println(clazz2.getClassLoader());

//运行结果:
//分别打印出 两个 新创建的类加载器
//MyClassLoaderTest$MyClassLoader@266474c2
//MyClassLoaderTest$MyClassLoader@66d3c617

项目连接

请配合项目代码食用效果更佳:
项目地址:
https://github.com/hesuijin/hesuijin-study-project
Git下载地址:
https://github.com.cnpmjs.org/hesuijin/hesuijin-study-project.git

jvm-module项目模块下  classLoader包   

你可能感兴趣的:(3:类加载机制深度解析(Tomcat打破双亲委派机制)(文末有项目连接))