在刚刚接触Java的时候就对类的加载体系做过一个小小的总结,但是现在感觉很有必要再次总结一下。
一、类的加载方法
1、ClassLoader的的基本概念:
与c与c++编写的程序不同,Java程序并不是可执行文件,而是有许多的类文件组成,每个文件对应一个Java类。而且这些类并不是全部装进内存,而是根据程序运行的需要逐步装载。ClassLoader是JVM的实现的一部分。
2、ClassLoader的加载流程
当运行第一个程序的时候JVM启动,运行bootstrap classloader,该加载器负责加载核心Java API,然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下面定义的Class。
首先我们应该要知道ClassLoader除了将Class加载到JVM中之外,还有一个重要的作用就是审查每个类应该由谁进行加载,这是一种父类优先的机制。
除了这两个作用还有就是将Class字节码重新解析成JVM统一要求的格式。
下面是ClassLoader类的loadClass方法:
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // First, check if the class has already been loaded Class c = findLoadedClass(name); //该类还没有被加载,那么则 if (c == null) { try { //如其父类不为空,那么则使用其父类进行加载(父类委托机制) if (parent != null) { c = parent.loadClass(name, false); } //如果其父类为空则使用BootstrapClass进行加载 else { c = findBootstrapClass0(name); } } catch (ClassNotFoundException e) { // If still not found, then invoke findClass in order // to find the class. //如果此类的父类加载器无法加载该类,那么有此类加载器的findClass进行类字节码 的加载 c = findClass(name); } } //是否需要解析类,如果resolve=true时,则保证已经装载,而且已经连接了。resolve=falses时,则仅仅是去装载这个类,不关心是否连接了,所以此时可能被连接了,也可能没有被连接 if (resolve) { resolveClass(c); } return c; }
上面的代码可以看出,一个类的加载过程使用了一种父类委托的模式,这种模式的好处主要有两种:
1、可以避免重复加载,当父类已经加载了该类的时候就没有必要子ClassLoader再加载一次。
2、考虑到安全因素,如果不使用这种委托模式,那么可以随时使用自定义的String来动态代替Java核心API中定义的类型,这样做会存在非常大的安全隐患,而父类委托模式就可以避免这种情况,因为服加载器已经在启动时被加载,所以,用户自定义类是无法加载一个自定义的String的。
除了上面的loadClass方法外方法还有几个比较重要的
protected final Class<?> defineClass protected Class<?> findClass(String name) protected final void resolveClass(Class<?> c)
上面的loadClass方法的作用只是启动类的加载,指定类应该由谁进行加载。而具体的怎么加载需要用到
defineClass方法:其能够将byte字节流解析成JVM能够识别的Class对象。
然后还有一个findClass方法:
findClass:负责取得需要加载的类的字节码,然后可以调用definedClass方法生成类的Class对象。
有了这样两个方法我们不仅仅可以通过class文件实例化对象,还可以通过网络接受字节码实例化对象。
一般我们配合使用defineClass和findClass 方法,直接覆盖ClassLoader父类的findClass方法来实现类的加载规则,findClass取得需要加载的类的字节码,defineClass根据字节码创建类对象
破坏双亲委派模型
双亲委派模型第一次被破坏:
双亲委派模型在jdk1.2的时候才被引入,提供了findClass方法供用户进行重写以指定自己的类加载规则,但是在jdk1.2之前用户继承ClassLoader的目的就是为了重写loadClass方法,但是双亲委派的具体逻辑就实现在这个方法之中,所以在JDK1.2之后就不提倡用户覆盖loadClass方法,而应当把自己得把类加载逻辑卸载findClass方法中,如果父类加载其加载失败会调用自己的findClass进行类的加载,这样就可以保证心写出来的类加载器符合双亲委派模型。
双亲委派模型第二次被破坏:
双亲委派模型的第二次破坏是由这个模型本身造成的,这个模型中是越基础的类越由上层的加载器加载,之所以基础是因为他们总是被作为用户调用的API但是事无绝对,如果基础类又要调用用户的代码怎么办???
一个典型的例子就是JNDI,他的代码由启动类进行加载,但是JNDI的目的是对资源进行集中管理和查找,他需要调下用调用独立厂商实现并部署在应用程序ClassPath
下的JNDI接口提供者,这个问题的解决是在程序中引入了不太优雅的设计:线程上下文类加载器,JNDI可以使用这个线程上下文类加载器去加载所需要的SPI,也就是父类加载器请求自类加载器去完成类加载的动作,这已经违反了双亲委派模型的一般性原则,在Java中所有涉及SPI的如jNDI , JDBC , JCE , JAXB和JBI都使用这种模型来进行类的加载。
双亲委派模型第三次被破坏:
这里主要是说OSGI为了实现Java模块化热部署而自定义的类加载机制的实现。它把双亲委派模型的树状结构改编成了自己的更加复杂的网状结构,具体的这里已经暂时超过了小菜的讨论范围
相关推荐
深入研究Java类加载机制 深入研究Java类加载机制 深入研究Java类加载机制 深入研究Java类加载机制
此外,我们还会探讨Java程序的类加载器和双亲委派机制,以及自定义类加载器和类卸载的实现原理和应用方法。 总的来说,本资源将为Java程序员提供全面的Java字节码和类加载原理和实践经验。通过学习本资源,开发人员将...
java 类加载机制,课程笔记。
经典的java虚拟机类加载机制 看完后会有醍醐灌顶的感觉
类加载机制及反射 类加载机制及反射
Java的类加载机制:加载,连接,初始化。JAVA类加载器: Bootstrap ClassLoader : 根类加载器, Extension ClassLoader: 扩展类加载器, System ClassLoader : 系统类加载器, Java反射
Android类加载机制、插件化、热修复相关内容。Android类加载机制、插件化、热修复相关内容。Android类加载机制、插件化、热修复相关内容。Android类加载机制、插件化、热修复相关内容。Android类加载机制、插件化、...
深入BREW模块加载机制.doc,深入BREW模块加载机制.doc,深入BREW模块加载机制.doc,深入BREW模块加载机制.doc
关于java深入类加载机制.md
类加载器是 Java 语言的一个创新,也是 ...不过如果遇到了需要与类加载器进行交互的情况,而对类加载器的机制又不是很了解的话,就很容易花大量的时间去调试 ClassNotFoundException和 NoClassDefFoundError等异常。
深入研究Java的类加载机制.pdf
该文件是JVM中关于类加载机制的知识整理的思维导图,包括类加载机制概述、类加载的生命周期、加载时机、加载过程、类加载、类的初始化和实例化等几个大方面进行了讲解,其中类加载中还对JVM三种预定义类加载器进行了...
类加载机制PPT+代码
Android 热修复框架 (基于类加载机制的代码修复)
作者:【郭孝星】http://blog.csdn.net/allenwells 微博:【郭孝星的新浪微博】http://weibo.com/allenwells 邮箱:allenwells@163.com 博客:http://blog.csdn.net/allenwells Github:...
深层次剖析java的类加载机制。讲解java类加载的服装流程。
虚拟机把描述类的数据从Class文件中加载到内存,并对数据进行校验、转换解析和初始化,最终形成可被虚拟机直接使用的Java类型,这就是虚拟机加载机制。
讲解JVM的ClassLoader子系统原理.
对jvm内存模型&垃圾收集算法&类加载机制进行了整理,读者可以作为参考进行学习和探讨,,
NULL 博文链接:https://yjhexy.iteye.com/blog/668334