采用双亲委托机制的原因

  类加载器就是将字节码搬进jvm方法区的组件。我们知道,JVM识别加载进来的类是通过类加载器+类全名完成的,也就是说同一个类由不同类加载器加载进去的话就会被视为不同的类。jdk提供的类加载器及他们的关系如下:

我们可以自己继承ClassLoader定义多个自己的类加载器,但是这多个类加载器去加载同一个类(例如java.lang.Integer)就会多次加载这个类,jvm也会将这两次加载的Integer类看成不同的类,因为加载器不是同一个。而我们希望的是,对于这种核心基础类,只需加载一个就行了。此外,我们甚至可以自定义一个Integer类,用自定义的加载器加载进去,这对于程序来说是不安全的。

基于以上两个原因,Java采用了双亲委托机制。工作流程:

  1. 当前ClassLoader首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。每个类加载器都有加载缓存,当一个类被加载了以后就会放入缓存,下次加载的时候就可以直接返回。

  2.  当前classLoader的缓存中没有找到被加载的类的时候,委托父类加载器去加载,父类加载器采用同样的策略,首先查看自己的缓存,然后委托父的父去加载,一直到BootStrapClassLoader.

  3.  到BootStrapClassLoader都没有发现缓存的话,就开始主动加载。(加载成功将其放入它自己的缓存中,以便下次有加载请求的时候直接返回)

  4. 如果BootStrapClassLoader在自己负责加载的文件夹中找不到目标类,则将任务交给下一层主动加载,不成功继续交给下一层主动加载。

总结:先层层往上找有没有缓存,到顶后还没缓存就主动加载,失败就层层往下尝试。

因此使用此机制原因归为:

  1. 使类加载器有优先关系,防止了重复加载。父类加载了子类便不会去加载。例如:核心的基础类只会被引导类加载器加载,保证了核心基础类在jvm的唯一性即一个类总是由一个类加载器加载

  2. 更安全。冒充核心类名的类最终总是到引导类记载器。保证了核心基础类的正确性即只会加载指定包中唯一的类

破坏双亲委托机制的情形

  双亲委托机制并不是强制使用的,我们可以继承java.lang.ClassLoader类,实现自己的类加载器。如果想保持双亲委派模型,就应该重写findClass(name)方法;如果想破坏双亲委派模型,可以重写loadClass(name)方法。

  下面例举破坏双亲模型的情形。

1. Tomcat

  Tomcat是一个servlet容器,他也是Java编写的,需要运行在JVM之上。我们编写的服务端程序即servlet部署在tomcat中才是完整的服务端程序(tomcat完成了与客户端通信、管理servlet生命周期等功能)。一般生产环境下,一个Tomcat中会运行着多个servlet,这个时候我们就不应该使用双亲模型了。原因是多个servlet应该是完全隔离的,而使用双亲模型,多个服务器程序就是共用一套类库了,这样各种错误都来了。

  正确的做法是,每个部署在tomcat中的servlet都有自己的WebAppClassLoader,加载类时直接使用它加载,这样各个servlet加载的类互不干涉。

  一个Tomcat启动会伴随一个JVM进程的启动(因为Tomcat也是Java编写的),多个部署在Tomcat的应用可以互不干涉的运行在这一个JVM中,正式因为破坏了双亲委托机制。

2. JDBC

  使用JDBC建立数据库连接:

Connection con = DriverManager.getConnection(url , username , password ) ; 

JDBC的Driver接口定义在JDK中,但是其具体实现由各个数据库的服务商来提供,比如MySQL驱动包。

DriverManager 类位于 $JAVA_HOME中jre/lib/rt.jar 包,由BootStrap类加载器加载,而其具体Driver实现类是位于服务商提供的 Jar 包。根据类加载机制,当被装载的类引用了另外一个类的加载时候,虚拟机就会使用装载第一个类的类装载器装载被引用的类,也就是说BootStrap类加载器还要去加载jar包中的Driver接口的实现类,但BootStrap类加载器默认只负责加载 $JAVA_HOME中jre/lib里的class,所以又需要由子类加载器去加载Driver实现,这就破坏了双亲委派模型。

实际的Tomcat类加载机制

  既然Tomcat破坏了双亲模型,那么是否表示他可能会装载到自定义的有害的基础类呢?先看看Tomcat类加载器的结构(图片来源于网络https://www.cnblogs.com/aspirant/p/8991830.html):

  • commonLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;
  • catalinaLoader:Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;
  • sharedLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;
  • WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见;

每个应用在部署后,都会创建一个唯一的类加载器,即自己的WebAppClassLoader,该类加载器会加载的类仅仅对本应用可见。Web应用程序的WebApp类加载器加载类要加载某类时,该类加载器将首先查找自己负责的文件夹中是否存在此类,而不是向父加载器委派。也有例外,属于JRE基类的类不能如此,还是要走双亲委派。

  综上,Tomcat也有一套层次结构的类加载器,加载JRE基类时还是走双亲委派,其他就是优先使用WebApp加载器加载。因此,即使破坏了双亲模型,Tomcat类加载也不会有安全问题。

破坏双亲委托机制的一些情况---Tomcat和JDBC,破坏后的安全问题的更多相关文章

  1. JAVA基础|从Class.forName初始化数据库到SPI破坏双亲委托机制

    代码托管在:https://github.com/fabe2ry/classloaderDemo 初始化数据库 如果你写过操作数据库的程序的话,可能会注意,有的代码会在程序的开头,有Class.for ...

  2. ClassLoader类加载器 & Java类加载机制 & 破坏双亲委托机制

    ClassLoader类加载器 Java 中的类加载器大致可以分成两类: 一类是系统提供的: 引导类加载器(Bootstrap classloader):它用来加载 Java 的核心库(如rt.jar ...

  3. Java 类加载体系之 ClassLoader 双亲委托机制

    Java 类加载体系之 ClassLoader 双亲委托机制 java 是一种类型安全的语言,它有四类称为安全沙箱机制的安全机制来保证语言的安全性,这四类安全沙箱分别是: 类加载体系 .class文件 ...

  4. jdbc 加载数据库驱动如何破坏双亲委托模式

    导读      通过jdbc链接数据库,是每个学习Java web 方向的人必然一开始会写的代码,虽然现在各路框架都帮大家封装好了jdbc,但是研究一下jdbc链接的套路还是很意义     术语以及相 ...

  5. JVM 类加载器的双亲委托机制

    1.类加载器的层次结构 在双亲委托机制中,各个加载器按照父子关系形成了树形结构(逻辑意义),除了根加载器之外,其余的类加载器都有且只有一个父加载器. public class MyTest13 { p ...

  6. 【JVM学习笔记】双亲委托机制存在的意义

    1.可以确保Java核心库的类型安全:所有的Java应用都至少会引用java.lang.Object类,也就是说在运行期,java.lang.Object这个类会被加载到Java虚拟机:如果用户自定义 ...

  7. 【JVM学习笔记】打破双亲委托机制的例子

    Tomcat也有自己的类加载器,比如Servlet,这些类加载器就改变了双亲委托模型的默认机制 (该主题有待深入)

  8. 说一说JVM双亲委派机制与Tomcat

    双亲委派模型与JVM 类加载 讲个故事: 以前,爱捣鼓的小明突然灵机一动,写出了下面的代码 package java.lang; public class String { //...复制真正Stri ...

  9. [转帖]说一说JVM双亲委派机制与Tomcat

    说一说JVM双亲委派机制与Tomcat https://www.cnblogs.com/dengchengchao/p/11844022.html 讲个故事: 以前,爱捣鼓的小明突然灵机一动,写出了下 ...

随机推荐

  1. 《SQL Server 2012 T-SQL基础》读书笔记 - 5.表表达式

    Chapter 5 Table Expressions 一个表表达式(table expression)是一个命名的查询表达式,代表一个有效的关系表.SQL Server包括4种表表达式:派生表(de ...

  2. 网络流小记(EK&dinic&当前弧优化&费用流)

    欢 迎 来 到 网 络 瘤 的 世 界 什么是网络流? 现在我们有一座水库,周围有n个村庄,每个村庄都需要水,所以会修水管(每个水管都有一定的容量,流过的水量不能超过容量).最终水一定会流向唯一一个废 ...

  3. 图论&线性基(?)(8.12)

    边没有负权,最短路最多只有n条边 很暴力的思想: 先跑一遍最短路,找出最短路上的边,枚举每条边,翻倍,放进原图再跑一遍.取最大值 好熟悉啊 分层建图,建k层 每层内部是原图 若原图中u到v有连边,则由 ...

  4. (转)oracle触发器使用:after insert 与before insert的简单使用注意

    本文转载自:http://blog.csdn.net/kuangfengbuyi/article/details/41446125 创建触发器时,触发器类型为after insert , 在begin ...

  5. 如何查看yum安装的程序包都放在哪些地方了?

    yum安装, 是先下载下来, 然后安装, 用dnf代替yum后, 配置文件跟yum类似, 也是放在 /etc/dnf/ 目录下的, 也有dnf.conf 配置文件等 dnf list后面还可以跟参数: ...

  6. 查看linux显卡序列

    1 lspci -vnn | grep VGA -A 12会输出显卡的硬件信息,第一行的第二个[]内是显卡的序列号2 在网站http://pci-ids.ucw.cz/read/PC/ 下方输入序列号 ...

  7. Matplotlib字体大小设置

    参考:https://blog.csdn.net/henkekao/article/details/72871882 ax = plt.subplot(111) # 设置刻度字体大小 plt.xtic ...

  8. [19/05/25-星期六] JavaScript_ 基础知识和基本语法_数据类型

    一.概念 诞生于1995年,刚开始主要用于处理网页中的前端验证(指的是检查用户输入的内容是否符合一定的规则,比如用户名的长度.密码的长度.邮箱格式等). 前身是网景公司的LiveScript语言,傍的 ...

  9. spring data solr 搜索关键字高亮显示

    spring data solr 搜索关键字高亮显示 public Map<String, Object> highSearch(Map searchMap) { Map map = ne ...

  10. dp(最大分段和)

    http://acm.hdu.edu.cn/showproblem.php?pid=1024 Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Othe ...