ClassLoader以及双亲委托模式
来源:互联网 发布:linux下shell编程技巧 编辑:程序博客网 时间:2024/05/21 14:49
站在虚拟机的角度上,只存在两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),这个类加载器使用C++语言实现,是虚拟机自身的一部分;另外一种就是其它所有的类加载器,这些类加载器都由Java语言实现,独立于虚拟机外部,并且全部继承java.lang.ClassLoader。
从Java开发人员的角度看,类加载器还可以划分得更细一些,如下:
1.启动类加载器(Bootstrap ClassLoader):这个类加载器不是用java语言所编写的,而是JVM实现的一部分,负责将放置在<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数所指定路径中的,并且是虚拟机能识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放置在lib目录中也不会被加载)类库加载到虚拟机内存中。启动类加载器无法被Java程序直接使用。2.扩展类加载器(Extension ClassLoader):这个类加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载<JAVA_HOME>\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。
3.应用程序类加载器(Application ClassLoader):这个类加载器由sum.misc.Launcher.$AppClassLoader来实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也被称为系统类加载器。它负责加载用户类路径上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
应用程序由这三种类加载器互相配合进行加载的,如果有必须,还可以加入自己定义的类加载器。这些类加载器之间的关系一般如下图:
上图中展示的类加载器之间的层次关系,就称为类加载器的双亲委派模型(Parents Delegation Model)。双亲委派模型要求除了顶层的启动类加载器之外,其余的类加载器都应当有自己的父类加载器。这里的类加载器之间的父子关系一般不会以继承的关系来实现,而是使用组合关系来复用父加载器的代码。
为什么要采用双亲委派模型:
主要是解决类载入过程安全性问题,如果不采用双亲委派模型,用户自己写了一个java.lang.Object类,系统将会出现多个Object类,程序将一片混乱。
双亲委派模型的式作过程是:
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完全这个加载请求时,子加载器才会尝试自己去加载。
如何打破双亲委派模型:
打破双亲委派机制则不仅要继承ClassLoader类,还要重写loadClass和findClass方法,如下例子:
①定义Test类
public class Test { public Test(){ System.out.println(this.getClass().getClassLoader().toString()); }}②重新定义一个继承ClassLoader的TestClassLoaderN类,这个类与前面的TestClassLoader类很相似,但它除了重写findClass方法外还重写了loadClass方法,默认的loadClass方法是实现了双亲委派机制的逻辑,即会先让父类加载器加载,当无法加载时才由自己加载。这里为了破坏双亲委派机制必须重写loadClass方法,即这里先尝试交由System类加载器加载,加载失败才会由自己加载。它并没有优先交给父类加载器,这就打破了双亲委派机制。
public class TestClassLoaderN extends ClassLoader { private String name; public TestClassLoaderN(ClassLoader parent, String name) { super(parent); this.name = name; } @Override public String toString() { return this.name; } @Override public Class<?> loadClass(String name) throws ClassNotFoundException { Class<?> clazz = null; ClassLoader system = getSystemClassLoader(); try { clazz = system.loadClass(name); } catch (Exception e) { // ignore } if (clazz != null) return clazz; clazz = findClass(name); return clazz; } @Override public Class<?> findClass(String name) { InputStream is = null; byte[] data = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { is = new FileInputStream(new File("d:/Test.class")); int c = 0; while (-1 != (c = is.read())) { baos.write(c); } data = baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); } finally { try { is.close(); baos.close(); } catch (IOException e) { e.printStackTrace(); } } return this.defineClass(name, data, 0, data.length); } public static void main(String[] args) { TestClassLoaderN loader = new TestClassLoaderN( TestClassLoaderN.class.getClassLoader(), "TestLoaderN"); Class clazz; try { clazz = loader.loadClass("test.classloader.Test"); Object object = clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); } } }
阅读全文
0 0
- ClassLoader以及双亲委托模式
- android classloader双亲委托模式
- java双亲委托模式classLoader
- classloader加载的双亲委托模式
- Java ClassLoader及双亲委托模式
- classloader和双亲加载模式
- java ClassLoader类解析-双亲委托机制
- 理解ClassLoader双亲委托模型关键
- java ClassLoader类解析-双亲委托机制
- JVM类加载-从ClassLoader源码看双亲委托模型
- Java类加载双亲委托模式优点
- 浅谈Java 类加载器以及双亲委托机制
- 双亲委托模型
- ClassLoader和双亲委派机制
- JVM学习----ClassLoader、双亲委派
- 【jvm】---classLoader 双亲委派模型
- ClassLoader双亲委派模型loadClass过程
- 双亲加载模式
- 洛谷P1171 售货员的难题
- 堆排序(C语言版本)
- 爬取网页内所有的url和meta标签,title标签
- Linux下如何配置Kafka Cluster (Kafka族)
- 怎样快速判断掩码第一个为1的Bit位置
- ClassLoader以及双亲委托模式
- 在 SQLite3 中使用回调函数
- php 调用java php-java-bridge
- POJ_3420_Quad Tiling
- ADXL345串口输出
- c++第二节课
- 闭包
- 为什么中国的程序员总被称为码农?
- C#快速入门