JVM双亲委派模型
Java类加载器
双亲委派模式要求除了顶层的BootstrapClassLoader之外,其余的类加载器都应当有自己的父类加载器,双亲委派模式中的父子关系并非通常所说的类继承关系,而是采用组合关系来复用父类加载器的相关代码
-
类加载器之间的关系如下:
-
类装载方式:
- 隐式装载,程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中。
- 显式装载, 通过class.forName()等方法,显式加载需要的类
-
类加载的动态性体现:
一个应用程序总是由n多个类组成,Java程序启动时,并不是一次把所有的类全部加载后再运行,它总是先把保证程序运行的基础类一次性加载到jvm中,其它类等到jvm用到的时候再加载,这样的好处是节省了内存的开销,因为java最早就是为嵌入式系统而设计的,内存宝贵,这是一种可以理解的机制,而用到时再加载这也是java动态性的一种体现
双亲委派模型的工作原理
当一个类加载器收到了类加载请求后,他并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,一次递归,最终找到最顶层的BootstrapClassLoader,如果父类加载器可以完成此类加载任务,则成功返回,否则父类加载器会抛出异常,通知子类加载器自己去加载,这是子类加载器才会尝试自己去加载,这就是双亲委派模型。
-
双亲委派模型的优势:
- 采用双亲委派模型的好处是Java类随着他的类加载器一起具备了一种带有优先级的层次关系,通过这种层次关系可以避免类的重复加载,当父亲已经加载了类的时候,就没有必要子ClassLoader在加载一次。
- 其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。
-
类加载器(ClassLoader) JVM加载class文件的原理机制
类装载器就是寻找类或接口字节码文件进行解析并构造JVM内部对象表示的组件,在java中类装载器把一个类装入JVM,经过以下步骤:
- 装载: 查找和导入Class文件
- 链接:其中解析步骤是可以选择的
- 检查:检查载入的class文件数据的正确性
- 准备:给类的静态变量分配存储空间
- 解析:将符号引用转成直接引用
- 初始化:对静态变量,静态代码块执行初始化工作
类装载工作由ClassLoder和其子类负责。JVM在运行时会产生三个ClassLoader:Bootstrap(根装载器),ExtClassLoader(扩展类装载器)和AppClassLoader(应用类加载器)。
-
其中根装载器不是ClassLoader的子类,由C++编写,因此在java中看不到他,负责装载JRE的核心类库,如JRE目录下的rt.jar,charsets.jar等。
-
ExtClassLoader是ClassLoder的子类,负责装载JRE扩展目录ext下的jar类包。
-
AppClassLoader负责装载classpath路径下的类包。
这三个类装载器存在父子层级关系,即根装载器是ExtClassLoader的父装载器,ExtClassLoader是AppClassLoader的父装载器。默认情况下使用AppClassLoader装载应用程序的类。