1、Java类加载过程
根据JVM规范,JVM内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分。
JAVA类的加载过程,详细说下来便是,先将.java文件编译成.class文件。然后,在通过类加载器,将class文件加载到JVM中,然后在运行,输出结果。
2、什么是双亲委派机制
先说类加载器,只存在两种不同的类加载器: 启动类加载器( Bootstrap ClassLoader),利用 C++实现,是虚拟机自身的一部分。另一种是 所有其他的类加载器,利用 JAVA实现,独立于JVM,并且全部 继续自抽象类java.lang.ClassLoader.
每个类加载器都有固定的查找类的路径,在 JDK8 的时候一共有三种类加载器。
启动类加载器(Bootstrap ClassLoader),它是属于虚拟机自身的一部分,用 C++ 实现的,紧张卖力加载\lib目录中或被 -Xbootclasspath 指定的路径中的并且文件名是被虚拟机识别的文件。它是所有类加载器的爸爸。扩展类加载器(Extension ClassLoader),它是 Java 实现的,独立于虚拟机,紧张卖力加载\lib\ext目录中或被 java.ext.dirs 系统变量所指定的路径的类库。运用程序类加载器(Application ClassLoader),它是Java实现的,独立于虚拟机。紧张卖力加载用户类路径(classPath)上的类库,如果我们没有实现自定义的类加载器那这玩意便是我们程序中的默认加载器。双亲委派模型并不是一个逼迫性的模型,仅是推举,双亲委派模型的事情过程是: 当一个类加载器受到类加载要求,它首先不会自己考试测验去加载这个类,而是把这个要求委派给自己的父类加载器去完成,只有当父加载器表示自己无法完成这个加载要求时,子加载器才会考试测验自己去加载。
这个模型的好处,便是担保某个范围的类一定是被某个类加载器所加载的,这就担保在程序中同一个类不会被不同的类加载器加载。这样做的一个紧张的考量,便是从安全层面上,杜绝通过利用和JRE相同的类名伪装现有JRE的类达到更换的攻击办法。
3、哪些场景冲破了双亲委派
至此我们已经清楚了什么是双亲委派,和为什么要双亲委派。接下来我们来看看三次毁坏。
第一次毁坏在 jdk 1.2 之前,那时候还没有双亲委派模型,不过已经有了 ClassLoader 这个抽象类,以是已经有人继续这个抽象类,重写 loadClass 方法来实现用户自定义类加载器。
而在 1.2 的时候要引入双亲委派模型,为了向前兼容, loadClass 这个方法还得保留着使之得以重写,新搞了个 findClass 方法让用户去重写,并呼吁大家不要重写 loadClass 只要重写 findClass。
这便是第一次对双亲委派模型的毁坏,由于双亲委派的逻辑在 loadClass 上,但是又许可重写 loadClass,重写了之后就可以毁坏委派逻辑了。
第二次毁坏第二次毁坏指的是 JNDI、JDBC 之类的情形。
首先得知道什么是 SPI(Service Provider Interface),它是面向拓展的,也便是说我定义了个规矩,便是 SPI ,详细如何实现由扩展者实现。
像我们比较熟的 JDBC 便是如此。
MySQL 有 MySQL 的 JDBC 实现,Oracle 有 Oracle 的 JDBC 实现,我 Java 不管你内部如何实现的,反正你们这些数据库厂商都得统一按我这个来,这样我们 Java 开拓者才能随意马虎地调用数据库操作,以是在 Java 核心包里面定义了这个 SPI。
而核心包里面的类都是由启动类加载器去加载的,但它的手只能摸到\lib或Xbootclasspath指定的路径中,其他的它鞭长莫及。
而 JDBC 的实现类在我们用户定义的 classpath 中,只能由运用类加载器去加载,以是启动类加载器只能委托子类来加载数据库厂商们供应的详细实现,这就违反了自下而上的委托机制。
详细办理办法是搞了个线程高下文类加载器,通过setContextClassLoader()默认情形便是运用程序类加载器,然后利用Thread.current.currentThread().getContextClassLoader()得到类加载器来加载。
这便是第二次毁坏双亲委派模型。
第三次毁坏这次毁坏是为了知足热支配的需求,一直机更新这对企业来说至关主要,毕竟停机是大事。
OSGI 便是利用自定义的类加载器机制来完成模块化热支配,而它实现的类加载机制就没有完备遵照自下而上的委托,有很多平级之间的类加载器查找,详细就不展开了,有兴趣可以自行研究一下。
这便是第三次毁坏。
4、Tomcat冲破双亲委派机制
Tomcat 为实现隔离性,每个 webappClassLoader 加载自己目录下的 class 文件,而不会通报给父类加载器,冲破了双亲委派机制。
Tomcat 作为 web 容器须要担保:
一个 web 容器可能须要支配多个运用程序,不同的运用程序可能会依赖同一个第三方类库的不同版本,要担保每个运用程序的类库都是独立的、相互隔离的。支配在同一个 web 容器中相同的类库相同的版本可以共享。web 容器也有自己依赖的类库,不能与运用程序的类库稠浊。web 容器须要支持 jsp 修正,且不用重启。(即 jsp 热支配)如上图,Tomcat 的几个紧张类加载器,知足作为 web 容器须要办理的4个问题:
commonLoader :Tomcat最基本的类加载器,加载路径中的 class 可被 Tomcat 容器本身以及各个 Webapp 访问;catalinaLoader :Tomcat 容器是私有的类加载器,加载路径中的 class 对付 Webapp 不可见;sharedLoader :各个 Webapp 共享的类加载器,加载路径中的 class 对付所有 Webapp 可见,但是对付 Tomcat 容器不可见;WebappClassLoader :各个 Webapp 私有的类加载器,实现相互隔离。仿照实现Tomcat 的 webappClassLoader 加载war运用内不同版本类实现相互共存与隔离