文章目录

  • 类加载的本质
  • JVM 双亲委派机制
    • BootstrapClassLoader(启动类加载器)
    • ExtensionClassLoader
    • AppClassLoader
  • Tomcat的 类加载顺序
    • Tomcat要解决什么问题?
    • Tomcat违反了双亲委派机制?
    • Tomcat加载机制小结
  • Tomcat 热加载JasperLoader
  • 常见错误
    • NoClassDefFoundError
    • NoSuchMethodError
    • ClassCastException


类加载的本质

ClassLoader是用来加载 Class 的。它负责将 Class 的字节码形式转换成内存形式的 Class 对象。

字节码可以来自于磁盘文件 *.class,也可以是 jar 包里的 *.class,也可以来自远程服务器提供的字节流,字节码的本质就是一个字节数组 []byte,它有特定的复杂的内部格式。

JVM 运行实例中会存在多个 ClassLoader,不同的 ClassLoader 会从不同的地方加载字节码文件。

它可以从不同的文件目录加载,也可以从不同的 jar 文件中加载,也可以从网络上不同的静态文件服务器来下载字节码再加载。


JVM 双亲委派机制

Java1.2之后引入双亲委派模式 。

核心原理: 如果其中一个类加载器收到了类加载的请求,它并不会自己去加载而是会将该请求委托给父类的加载器去执行,如果父类加载器还存在父类加载器,则进一步向上委托,如此递归,请求最终到达顶层的启动类加载器。

如果父类能加载,则直接返回,如果父类加载不了则交由子类加载,这就是双亲委派模式。

好处

  • 向上委托给父类加载,父类加载不了再自己加载
  • 避免重复加载,防止Java核心api被篡改

BootstrapClassLoader(启动类加载器)

负责加载 JVM 运行时核心类,加载System.getProperty("sun.boot.class.path")所指定的路径或jar


ExtensionClassLoader

负责加载 JVM 扩展类,比如 swing 系列、内置的 js 引擎、xml 解析器 等等,这些库名通常以 javax 开头,它们的 jar 包位于 JAVAHOME/lib/rt.jar文件中.
加载System.getProperty("java.ext.dirs")所指定的路径或jar。

在使用Java运行程序时,也可以指定其搜索路径,例如:java -Djava.ext.dirs=d:\projects\testproj\classes HelloWorld


AppClassLoader

AppClassLoader才是直接面向我们用户的加载器,它会加载 Classpath 环境变量里定义的路径中的 jar 包和目录。

我们自己编写的代码以及使用的第三方 jar 包通常都是由它来加载的。

加载System.getProperty("java.class.path")所指定的路径或jar。

在使用Java运行程序时,也可以加上-cp来覆盖原有的Classpath设置,例如: java -cp ./lavasoft/classes HelloWorld


Tomcat的 类加载顺序

在Tomcat中,默认的行为是先尝试在Bootstrap和Extension中进行类型加载,如果加载不到则在WebappClassLoader中进行加载,如果还是找不到则在Common中进行查找 .

Common是公共的包, tomcat可以外挂很多个webapps (tomcat和app分开部署) ,优先以webapps下的为主。

tomcat7 —> 默认 WebappClassLoader 类加载器
tomcat 8 ---->默认 ParallelWebappClassLoader 类加载器


Tomcat要解决什么问题?

作为一个Web容器,Tomcat要解决什么问题 , Tomcat 如果使用默认的双亲委派类加载机制能不能行?

  1. 我们知道Tomcat可以部署多个应用,不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离 .

    举个例子 假设APP1 使用的是 Spring4 , APP2 使用的是Spring5 , 毫无疑问 Spring4 和 Spring 5 肯定有 类的全路径一样的类吧,如果使用双亲委派 ,父加载器加载谁?

  2. 部署在同一个web容器中相同的类库相同的版本可以共享, 比如jdk的核心jar包,否则,如果服务器有n个应用程序,那么要有n份相同的类库加载进虚拟机。

  3. web容器 自己依赖的类库 (tomcat lib目录下),不能与应用程序的类库混淆。基于安全考虑,应该让容器的类库和程序的类库隔离开来。

  4. web容器要支持jsp的修改, jsp 文件最终也是要编译成class文件才能在虚拟机中运行, web容器需要支持 jsp 修改后不用重启 ,就是热加载的功能。

结合上面的4个问题,我们看下双亲委派能不能支持?

第一个问题,如果使用默认的类加载器机制,肯定是无法加载两个相同类库的不同版本的,如果使用双亲委派,让父加载器去加载 ,不管你是什么版本的,只要你的全限定类名一样,那肯定只有一份,APP 隔离 无法满足

第二个问题,默认的类加载器是能够实现的,很好理解嘛, 就是双亲委派的功能,保证唯一性。

第三个问题和第一个问题一样。

第四个问题, 要怎么实现jsp文件的热加载呢? jsp 文件其实也就是class文件,那么如果修改了,但类名还是一样,类加载器会直接取方法区中已经存在的,修改后的jsp是不会重新加载的。那么怎么办呢?可以直接卸载掉这jsp文件的类加载器 .当一个jsp文件修改了,就直接卸载这个jsp类加载器。重新创建类加载器,重新加载jsp文件。 源码详见: org.apache.jasper.servlet.JasperLoader



Tomcat违反了双亲委派机制?

也不尽然,核心的Java的加载还是遵从双亲委派 。

Tomcat中 各个web应用自己的类加载器(WebAppClassLoader)会优先加载,打破了双亲委派机制。加载不到时再交给commonClassLoader走双亲委托 .

原因有二

  • 为了避免类冲突,每个 webapp 项目中各自使用的类库要有隔离机制
  • 不同 webapp 项目支持共享某些类库

Tomcat加载机制小结

当tomcat启动时,会创建几种类加载器:

  1. Bootstrap 引导类加载器 : 加载JVM启动所需的类,以及标准扩展类(位于jre/lib/ext下)

  2. System 系统类加载器 : 加载tomcat启动的类,比如bootstrap.jar,通常在catalina.bat或者catalina.sh中指定。位于CATALINA_HOME/bin


4. webapp 应用类加载器: 每个应用在部署后,都会创建一个唯一的类加载器。该类加载器会加载位于 WEB-INF/lib下的jar文件中的class 和 WEB-INF/classes下的class文件。

  1. Common 通用类加载器:加载tomcat使用以及应用通用的一些类,位于CATALINA_HOME/lib下,比如servlet-api.jar


总之 当应用需要到某个类时,则会按照下面的顺序进行类加载:

1 使用bootstrap引导类加载器加载 (JVM 的东西 )

2 使用system系统类加载器加载 (tomcat的启动类Bootstrap包)

3 使用WebAppClassLoader 加载 WEB-INF/classes (应用自定义的class)

4 使用WebAppClassLoader 加载在WEB-INF/lib (应用的依赖包)

5 使用common类加载器在CATALINA_HOME/lib中加载 (tomcat的依赖包,公共的,被各个应用共享的)


Tomcat 热加载JasperLoader

原理:后台启动线程监听jsp文件变化,如果变化了找到该jsp对应的servlet类的加载器引用(gcroot),重新生成新的JasperLoader加载器赋值给引用,然后加载新的jsp对应的servlet类,之前的那个加载器因为没有gcroot引用了,下一次gc的时候会被销毁。


常见错误

NoClassDefFoundError

NoClassDefFoundError : 由于JVM或者类加载器实例尝试加载类型的定义,但是该定义却没有找到,影响了执行路径。

换句话说,在编译时这个类是能够被找到的,但是在执行时却没有找到。


NoSuchMethodError

NoSuchMethodError代表这个类型确实存在,但是一个不正确的版本被加载了。 检查该类中是否真的有对应的方法


ClassCastException

ClassCastException,在一个类加载器的情况下,一般出现这种错误都会是在转型操作时,比如:A a = (A) method();,很容易判断出来method()方法返回的类型不是类型A,但是在 JavaEE 多个类加载器的环境下可能会出现一些不好去定位的情况。

Tomcat - 都说Tomcat违背了双亲委派机制,到底对不对?相关推荐

  1. 深入JVM系列(三)之类加载、类加载器、双亲委派机制与常见问题

    转载自 深入JVM系列(三)之类加载.类加载器.双亲委派机制与常见问题 一.概述 定义:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用 ...

  2. 类加载机制、双亲委派机制深度解析以及如何自定义类加载器

    文章目录 1.类加载运行的全过程 2. JVM类加载器的初始化 3.双亲委派机制 4.编写自定义类加载器 5.(Tomcat)如何打破双亲委派机制 当我们运行一个类的时候,首先要通过类加载机制把类加载 ...

  3. 【JVM】Java类的加载流程以及双亲委派,全盘托管,以及如何打破双亲委派机制

    JVM基础生命周期流程图 只有main()方法的java程序执行流程 classLoader.loadClass()的类加载流程(除引导类,所有类都一样) 加载:通过IO查找读取磁盘上的字节码文件,在 ...

  4. 如何打破双亲委派机制?

    上文:jdk-Launcher源码学习 背景 上文说过,jdk是通过双亲委派机制实现类的加载,但是这个加载效率及场景存在弊端,所以本文借鉴tomcat的实现方式去打破双亲委派机制实现自定义类加载器来模 ...

  5. Tomcat打破双亲委派机制

    打破双亲委派 沙箱安全机制示例,尝试打破双亲委派机制,用自定义类加载器加载自己实现的 java.lang.String.class public class MyClassLoaderTest {st ...

  6. JVM17_Tomcat打破双亲委派机制、执行顺序、底层代码原理、Tomcat|JDBC破坏双亲委派机制带来的面试题

    文章目录 ①. Tomcat类加载机制 ②. Tomcat执行顺序 ③. ClassLoader的创建 ④. ClassLoader加载过程 ⑤. Tomcat破坏双亲委派机制带来的面试题 ①. To ...

  7. 违反ClassLoader双亲委派机制三部曲第二部——Tomcat类加载机制

    转载自 违反ClassLoader双亲委派机制三部曲第二部--Tomcat类加载机制 前言: 本文是基于 ClassLoader双亲委派机制源码分析 了解过正统JDK类加载机制及其实现原理的基础上,进 ...

  8. java 双亲委派_JVM双亲委派机制与Tomcat

    双亲委派模型与JVM 类加载 讲个故事: 以前,爱捣鼓的小明突然灵机一动,写出了下面的代码 package java.lang; /** * @author dengchengchao * @date ...

  9. 如何打破双亲委派机制

    双亲委派机制 第一次知道何为打破双亲委派机制是通过阅读周志明的<深入理解Java虚拟机>,我们知道双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器 ...

最新文章

  1. 数据结构与算法(6-4)线索二叉树
  2. 如何让自学更有效率?
  3. python开发的优秀界面-八款常用的 Python GUI 开发框架推荐
  4. 寄语2013应届实习生
  5. linux多线程信号总结
  6. web-使用wsgiref模块模拟web框架
  7. Ubuntu 16.04安装SoapUI工具进行接口测试(Web Service/WSDL/RESTfull)
  8. 学习某一门技术的步骤(韩顺平老师提供)
  9. 灵活有效的激励手段-鲶鱼效应
  10. Golang内存分配逃逸分析
  11. 青藤 #10064 奇怪的电梯
  12. Ubuntu发烧友三部曲
  13. 第三十九期:1024特别版:向“程序媛们”致敬!
  14. 计算机硬盘灯不亮,解决办法:如果计算机硬盘驱动器指示灯不亮,该怎么办?解决电脑硬盘指示灯不亮的问题_IT / computer_资料...
  15. 方向导数和梯度(grad)
  16. 未转变者服务器车怎么得,未转变者刷车指令大全 | 手游网游页游攻略大全
  17. uint与int区别
  18. c语言忽略转义字符,C语言转义字符
  19. 苹果AppStore应用商店生存之道:国内iOS开发者创业经验分享(三)
  20. 随机生成双色球号码判断中奖模拟开奖python代码

热门文章

  1. 微型计算机中数据总线既可以传输数据信息,计算机考试题库精简版
  2. recyclervie刷新到底部_RecyclerView底部刷新实现详解
  3. A Deep Reinforcement Learning Network for Traffic Light Cycle Control 【论文阅读】
  4. C++引用不能绑定到临时数据
  5. AttributeError: module ‘grpc.experimental.aio‘ has no attribute ‘StreamUnaryCall‘
  6. scipy 笔记:solve_triangular
  7. PyTorch笔记: GPU上训练的模型加载到CPU/错误处理Attempting to deserialize object on a CUDA device but torch.cuda.is_a
  8. python库整理目录
  9. tableau应用实战案例(五十)-销售业绩的tableau可视化案例
  10. MATLAB应用实战系列(四十四)-基于matlab的支持向量机分类、回归问题(附源码解析)