采用双亲委托机制的原因

  类加载器就是将字节码搬进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. nodeName,nodeValue未知 xml 入库方案 The ElementTree iterparse Function

    import xml.etree.ElementTree as ET from lxml.html import * from xmljson import badgerfish as bf from ...

  2. malloc函数分配内存失败的常见原因

    malloc()函数分配内存失败的常见原因:  1. 内存不足.  2. 在前面的程序中出现了内存的越界访问,导致malloc()分配函数所涉及的一些信息被破坏.下次再使用malloc()函数申请内存 ...

  3. spring boot gateway自定义限流

    参考:https://blog.csdn.net/ErickPang/article/details/84680132 采用自带默认网关请参照微服务架构spring cloud - gateway网关 ...

  4. 腾讯视频的手机端的地址和PC端的地址是不一样的

    腾讯视频的手机端的地址和PC端的地址是不一样的,所以使用iframe的时候记得要使用手机端的地址

  5. linux自动化运维工具Ansible saltstack Puppet、Chef、Fabric之间的对比

    发现分布式是一个发展的趋势,无论是大型网站的负载均衡架构还是大数据框架部署,以及云存储计算系统搭建都离不开多台服务器的连续部署和环境搭建. 当我们的基础架构是分散式或者基于云的,并且我们经常需要处理在 ...

  6. es6基本介绍及使用

    1.什么是es6 ECMAScript 6.0(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了.它的目标,是使得JavaScript语言可以用来编写复杂的大型应 ...

  7. Eclipse解除已关联的Coding远程仓库,重新关联github上的远程仓库

    1.在Eclipse中的Git Repositories中找到要解除的仓库,依次找到Remote--origin[视自己的实际情况选择], 2.选中origin,右键选择Delete Remote , ...

  8. QToolButton设置icon的大小

    项目中用到了QToolButton上使用图片. 如果在maindow中直接使用QToolButton,如: btnSimulate = new QToolButton; btnSimulate-> ...

  9. 浏览器是怎样工作的:渲染引擎,HTML解析(连载二)

    转载自:http://ued.ctrip.com/blog/how-browsers-work-rendering-engine-html-parsing-series-ii.html 渲染引擎 渲染 ...

  10. sql 时间函数大全

    1.        当前系统日期.时间    select getdate() 2. dateadd  在向指定日期加上一段时间的基础上,返回新的 datetime 值  例如:向日期加上2天  se ...