Java虚拟机:类加载器与双亲委派模型
来源:互联网 发布:hadoop git 源码下载 编辑:程序博客网 时间:2024/05/17 02:52
学了挺久的java,也接触过java虚拟机,但是就是没有深入到源码中细细品读,也导致每次看到关于虚拟机的问题的时候都似曾相识却无从下手.这个系列就一点一点的品读java虚拟机.
类加载器
从java虚拟机规范描述来看,JVM支持两种类加载器:引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader).自定义类加载器派生于抽象类ClassLoader.
最常见的类加载器始终只有3个:
* Bootstrap ClassLoader 启动类加载器(引导加载器)
* ExtClassLoader
* AppClassLoader
对应来看,每种类加载器对应的目录为:
测试代码:
public class Test { public static void main(String[] args) { //BootstrapClassLoader ClassLoader classLoader = System.class.getClassLoader(); System.out.println(null != classLoader ? classLoader.getClass().getName(): "name:null"); //ExtClassLoader System.out.println(CollationData_ar.class.getClassLoader().getClass().getName()); //AppClassLoader System.out.println(Test.class.getClassLoader().getClass().getName()); }}
输出结果:
name:nullsun.misc.Launcher$ExtClassLoadersun.misc.Launcher$AppClassLoader
以上测试的含义是:
1. 因为java.lang.System类包含在JAVA_HOME/lib目录中,测试由BootstrapClassLoader加载,由于启动类加载器本身由C++编写并嵌套在JVM内部,所以输出为null.
2. sun.text.resoutces.CollationData_ar类包含在JAVA_HOME/lib/ext扩展目录中,由ExtClassLoader加载.
3. 而我们的一般测试类在ClassPath目录中,因此由AppClassLoader加载.
双亲委派模型
java程序中重要的一点是要保证一个类的全局唯一性.当程序中出现多个全限定名相同的类时,类加载器始终只加载其中的某一个类而不会都加载.
查看ClassLoader类中loadClass的源码:
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { //1.检查目标类之前是否已经被加载过了 synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { //如果存在超类加载器,就直接委派给顶层的启动类加载器. if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } 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 stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }
双亲委派模型的优点是使java类加载器具备优先级层级关系,越是基础的类越是被上层的类加载器加载,保证稳定运行.
**注意:**java虚拟机规范没有明确要求类加载器机制一定是双亲委派模型,只是建议.比如在Tomcat中,默认类加载器首先自己加载,失败时才给超类加载.
自定义类加载器
自定义类加载器的需求并不多.但是,当有一些特殊需求,比如,当一个字节码文件在编译的时候进行了加密处理,那么类加载器在加载的时候首先就要解密,否则会认为它不是标准的字节码文件.
自定义类加载器只需继承抽象类ClassLoader并重写ClassLoader.
注意:怎样查看当前的ClassPath目录?
System.getProperty("java.class.path");
准备工作
在F盘目录下创建Test1.java文件:
public Test1{ public static void main(String[] args){ System.out.println("test1"); }}
并在此打开命令行,用javac Test1.java 命令将其编译为Test1.class 文件.
程序代码
public class MyClassLoader extends ClassLoader { private String byteCode_Path; public MyClassLoader(String byteCode_Path) { this.byteCode_Path = byteCode_Path; } @Override protected Class<?> findClass(String className) throws ClassNotFoundException { byte value[] = null; BufferedInputStream in = null; try { in = new BufferedInputStream(new FileInputStream(byteCode_Path + className + ".class")); value = new byte[in.available()];//将字节码全部读取到数组里 in.read(value); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (null != in) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } return defineClass(value, 0, value.length);//将byte数组转化为一个class对象实例 } public static void main(String[] args) throws ClassNotFoundException { MyClassLoader classLoader = new MyClassLoader("F:/"); System.out.println("加载目标类的类加载器->"+classLoader.loadClass("Test1").getClassLoader().getClass().getName()); System.out.println("当前类加载器的超类加载器:->"+classLoader.getParent().getClass().getName()); }}
输出为:
加载目标类的类加载器->MyClassLoader当前类加载器的超类加载器:->sun.misc.Launcher$AppClassLoader
参考书目:《Java虚拟机精讲》 高翔龙
- Java虚拟机:类加载器与双亲委派模型
- 11.《深入理解Java虚拟机》类加载器与双亲委派模型
- 类加载器与双亲委派模型
- 类加载器与双亲委派模型
- 类加载器与双亲委派模型
- 类加载器与双亲委派模型
- 类加载器与双亲委派模型
- Java类加载器双亲委派模型
- java类加载器,双亲委派模型
- Java类加载器--双亲委派模型
- java类加载器与双亲委派模型
- java类加载器与双亲委派模型
- Java自定义类加载器与双亲委派模型
- 深入理解java虚拟机(九)类加载器以及双亲委派模型
- 黑马程序员【类加载器与双亲委派模型】
- 【深入理解JVM】:类加载器与双亲委派模型
- 双亲委派模型与自定义类加载器
- 【JVM】类加载器与双亲委派模型(一)
- sqlite数据库拷贝覆盖时,数据库大小恢复到原来大小,内容却是新数据库不分内容
- NZT在线源安装教程
- 读书笔记 effective c++ Item 15 在资源管理类中提供对原生(raw)资源的访问
- 【bzoj3295】动态逆序对 CDQ分治
- Jenkins+Dokcer,run一个docker demo
- Java虚拟机:类加载器与双亲委派模型
- Apache http 服务器如何启用和设置 https 连接以提供加密的 http 通讯教程
- 50行代码实现对抗生成网络GAN
- webpack中学习到的拓扑排序
- DNA Consensus String
- 递推等价-动态规划
- 正则表达式30分钟入门
- 安装Linux14.04详细步骤
- Struts2初步学习小结