打破双亲委派

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

public class MyClassLoaderTest {static class MyClassLoader extends ClassLoader {private String classPath;public MyClassLoader(String classPath) {this.classPath = classPath;}private byte[] loadByte(String name) throws Exception {name = name.replaceAll("\\.", "/");FileInputStream fis = new FileInputStream(classPath + "/" + name+ ".class");int len = fis.available();byte[] data = new byte[len];fis.read(data);fis.close();return data;}protected Class<?> findClass(String name) throws ClassNotFoundException {try {byte[] data = loadByte(name);return defineClass(name, data, 0, data.length);} catch (Exception e) {e.printStackTrace();throw new ClassNotFoundException();}}/*** 重写类加载方法,实现自己的加载逻辑,不委派给双亲加载* @param name* @param resolve* @return* @throws ClassNotFoundException*/protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException {synchronized (getClassLoadingLock(name)) {// First, check if the class has already been loadedClass<?> c = findLoadedClass(name);if (c == null) {// If still not found, then invoke findClass in order// to find the class.long t1 = System.nanoTime();c = findClass(name);// this is the defining class loader; record the statssun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}if (resolve) {resolveClass(c);}return c;}}}public static void main(String args[]) throws Exception {MyClassLoader classLoader = new MyClassLoader("D:/test");//尝试用自己改写类加载机制去加载自己写的java.lang.String.classClass clazz = classLoader.loadClass("java.lang.String");Object obj = clazz.newInstance();Method method= clazz.getDeclaredMethod("sout", null);method.invoke(obj, null);System.out.println(clazz.getClassLoader().getClass().getName());}
}运行结果:
java.lang.SecurityException: Prohibited package name: java.langat java.lang.ClassLoader.preDefineClass(ClassLoader.java:659)at java.lang.ClassLoader.defineClass(ClassLoader.java:758)

Tomcat打破双亲委派机制

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

  1. 一个web容器可能需要部署两个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。
  2. 部署在同一个web容器中相同的类库相同的版本可以共享。否则,如果服务器有10个应用程序,那么要有10份相同的类库加载进虚拟机。
  3. web容器也有自己依赖的类库,不能与应用程序的类库混淆。基于安全考虑,应该让容器的类库和程序的类库隔离开来。
  4. web容器要支持jsp的修改,我们知道,jsp 文件最终也是要编译成class文件才能在虚拟机中运行,但程序运行后修改jsp已经是司空见惯的事情, web容器需要支持 jsp 修改后不用重启。

Tomcat 如果使用默认的双亲委派类加载机制行不行?
答案是不行的。为什么?
第一个问题,如果使用默认的类加载器机制,那么是无法加载两个相同类库的不同版本的,默认的类加器是不管你是什么版本的,只在乎你的全限定类名,并且只有一份。
第二个问题,默认的类加载器是能够实现的,因为他的职责就是保证唯一性。
第三个问题和第一个问题一样。
再看第四个问题,要怎么实现jsp文件的热加载,jsp 文件其实也就是class文件,那么如果修改了,但类名还是一样,类加载器会直接取方法区中已经存在的,修改后的jsp是不会重新加载的。那么怎么办呢?可以直接卸载掉这jsp文件的类加载器,所以你应该想到了,每个jsp文件对应一个唯一的类加载器,当一个jsp文件修改了,就直接卸载这个jsp类加载器。重新创建类加载器,重新加载jsp文件。
以Tomcat类加载为例,Tomcat 如果使用默认的双亲委派类加载机制行不行?
我们思考一下:Tomcat是个web容器, 那么它要解决什么问题:

  1. 一个web容器可能需要部署两个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。
  2. 部署在同一个web容器中相同的类库相同的版本可以共享。否则,如果服务器有10个应用程序,那么要有10份相同的类库加载进虚拟机。
  3. web容器也有自己依赖的类库,不能与应用程序的类库混淆。基于安全考虑,应该让容器的类库和程序的类库隔离开来。
  4. web容器要支持jsp的修改,我们知道,jsp 文件最终也是要编译成class文件才能在虚拟机中运行,但程序运行后修改jsp已经是司空见惯的事情, web容器需要支持 jsp 修改后不用重启。

再看看我们的问题:Tomcat 如果使用默认的双亲委派类加载机制行不行?
答案是不行的。为什么?
第一个问题,如果使用默认的类加载器机制,那么是无法加载两个相同类库的不同版本的,默认的类加器是不管你是什么版本的,只在乎你的全限定类名,并且只有一份。
第二个问题,默认的类加载器是能够实现的,因为他的职责就是保证唯一性。
第三个问题和第一个问题一样。
我们再看第四个问题,我们想我们要怎么实现jsp文件的热加载,jsp 文件其实也就是class文件,那么如果修改了,但类名还是一样,类加载器会直接取方法区中已经存在的,修改后的jsp是不会重新加载的。那么怎么办呢?我们可以直接卸载掉这jsp文件的类加载器,所以你应该想到了,每个jsp文件对应一个唯一的类加载器,当一个jsp文件修改了,就直接卸载这个jsp类加载器。重新创建类加载器,重新加载jsp文件。

Tomcat自定义加载器详解


Tomcat的几个主要类加载器
commonLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个webapp访问
catalinaLoader:Tomcat容器私有的类加载器,加载路径中的class不可以为webapp可见
**shareLoader:**各个webapp共享的类加载器,加载路径中的class可以被所有的webapp访问,但是对于Tomcat容器不可见
**WebappClassLoader:**各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见,比如加载war包里相关的类,每个war包应用都有自己的WebappClassLoader,实现相互隔离,比如不同war包应用引入了不同的spring版本,这样实现就能加载各自的spring版本

tomcat 这种类加载机制违背了java 推荐的双亲委派模型了吗?答案是:违背了。
很显然,tomcat 不是这样实现,tomcat 为了实现隔离性,没有遵守这个约定,每个webappClassLoader加载自己的目录下的class文件,不会传递给父类加载器,打破了双亲委派机制。

模拟实现Tomcat的webappClassLoader加载自己war包应用内不同版本类实现相互共存与隔离

public class MyClassLoaderTest {static class MyClassLoader extends ClassLoader {private String classPath;public MyClassLoader(String classPath) {this.classPath = classPath;}private byte[] loadByte(String name) throws Exception {name = name.replaceAll("\\.", "/");FileInputStream fis = new FileInputStream(classPath + "/" + name+ ".class");int len = fis.available();byte[] data = new byte[len];fis.read(data);fis.close();return data;}protected Class<?> findClass(String name) throws ClassNotFoundException {try {byte[] data = loadByte(name);return defineClass(name, data, 0, data.length);} catch (Exception e) {e.printStackTrace();throw new ClassNotFoundException();}}/*** 重写类加载方法,实现自己的加载逻辑,不委派给双亲加载* @param name* @param resolve* @return* @throws ClassNotFoundException*/protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException {synchronized (getClassLoadingLock(name)) {// First, check if the class has already been loadedClass<?> c = findLoadedClass(name);if (c == null) {// If still not found, then invoke findClass in order// to find the class.long t1 = System.nanoTime();//非自定义的类还是走双亲委派加载if (!name.startsWith("com.tuling.jvm")){c = this.getParent().loadClass(name);}else{c = findClass(name);}// this is the defining class loader; record the statssun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}if (resolve) {resolveClass(c);}return c;}}}public static void main(String args[]) throws Exception {MyClassLoader classLoader = new MyClassLoader("D:/test");Class clazz = classLoader.loadClass("com.jvm.User1");Object obj = clazz.newInstance();Method method= clazz.getDeclaredMethod("sout", null);method.invoke(obj, null);System.out.println(clazz.getClassLoader());System.out.println();MyClassLoader classLoader1 = new MyClassLoader("D:/test1");Class clazz1 = classLoader1.loadClass("com.jvm.User1");Object obj1 = clazz1.newInstance();Method method1= clazz1.getDeclaredMethod("sout", null);method1.invoke(obj1, null);System.out.println(clazz1.getClassLoader());}
}运行结果:
=======自己的加载器加载类调用方法=======
com.jvm.MyClassLoaderTest$MyClassLoader@266474c2=======另外一个User1版本:自己的加载器加载类调用方法=======
com.jvm.MyClassLoaderTest$MyClassLoader@66d3c617

注意:同一个JVM内,两个相同包名和类名的类对象可以共存,因为他们的类加载器可以不一样,所以看两个类对象是否是同一个,除了看类的包名和类名是否都相同之外,还需要他们的类加载器也是同一个才能认为他们是同一个。

模拟实现Tomcat的JasperLoader热加载

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

User类的代码:

package com.jvm;public class User {private int id;private String name;public User() {}public User(int id, String name) {super();this.id = id;this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public void sout() {System.out.println("=======自己的加载器加载类调用方法=======");}
}

Tomcat打破双亲委派机制相关推荐

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

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

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

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

  3. 【有料】面试必备:什么时候要打破双亲委派机制?什么是双亲委派? (图解+秒懂+史上最全)

    面试题:什么时候要打破双亲委派机制 来自社群的两个面试题,其实也是两个基础的 面试题,大家一定要掌握 社群问题: 先说下第一题的结论 场景1: 如果委托类没有实现接口的话,就不能使用newProxyI ...

  4. Tomcat打破双亲委派模型

    tomcat的类加载器结构 在Tomcat目录结构中,有三组目录("/common/*","/server/*"和"shared/*")可以 ...

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

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

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

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

  7. 面试必备:什么时候要打破双亲委派机制?什么是双亲委派? (图解+秒懂+史上最全)

    文章很长,建议收藏起来慢慢读!疯狂创客圈总目录 语雀版 | 总目录 码云版| 总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 经典图书:<Java高并发核心编程(卷1)> 面试必备 ...

  8. 【04-JVM面试专题-什么是双亲委派机制(父类委托机制)?如何打破双亲委派机制?双亲委派机制的优缺点?什么是沙箱安全机制呢?】

    什么是双亲委派机制?如何打破双亲委派机制? JVM的双亲委派机制知道吗?怎么打破它呢?你看看自己掌握的怎么样呢? 什么是双亲委派机制?(父类委托机制) 检查某个类是否已经加载 自底向上,从Custom ...

  9. 双亲委派机制以及打破双亲委派机制

    双亲委派机制以及打破双亲委派机制 双亲委派机制 Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存中生成class对象,而且加载某个类的c ...

最新文章

  1. xp http文件服务器,在XP sp3下用IIS搭建http服务器总结
  2. python多变量拟合_python-使用scipy拟合多个参数曲线
  3. 算法笔记(一)——简述时间、空间复杂度分析
  4. [YTU]_2627 (职工工资统计)
  5. python元编程详解
  6. rsa.FromXmlString 系统找不到指定的文件
  7. 系统分析师考试结束了
  8. 32位CPU的机器只能支持4GB的内存吗?
  9. python调用腾讯自然语言处理api
  10. 集群节点数和分片数关系_离子晶体配位数与离子半径比的关系
  11. new image()
  12. 华为p20:拍美景,听讲解,旅行更智能
  13. span 超出部分换行
  14. 如何查看java安装成功_如何查看java是否安装成功
  15. mac系统下用wineskin安装plsql developer及数据乱码解决办法
  16. 【日常折腾】Y7000P拆机-更换触控板
  17. 计算机网络——常见协议
  18. 数据新闻大趋势 释放可视化报道的力量------读后随笔
  19. 百度地图开放平台天气预报查询API
  20. C语言笔记-10-函数空间-函数概念与规则

热门文章

  1. elasticsearch 集群无法启动出现如下提示 failed to send join request to master
  2. android 删除字符串中的指定字符
  3. java finally方法_讲解Java编程中finally语句的使用方法
  4. Cycript(一):基础简介
  5. Avalonia的资源和样式
  6. 深入浅出KNN算法(一) KNN算法原理
  7. mysql添加外键1215错误_MySQL添加外键时报错:1215 Cannot add the foreign key constraint的解决方法...
  8. fastran实例 -- 机翼静气弹分析
  9. C语言中左移(<<)和右移(>>)的理解
  10. Opencv copyTo() 与clone()的区别