目录
JVM四级类加载器(向上委托,向下加载,下可用上,上不可用下)
类加载过程
- –加载(loading)
- –链接(linking)
- •验证(Verification),字节码是否满足规范要求
- •准备(Preparation),分配内存,常量池初始化
- •解析(Resolution),解析类/接口/字段/方法的符号引用
3.–初始化(Initializing),执行类的初始化方法<clinit>
–类加载器是JVM生态体系的基础构成之一
–程序是依靠多个Java类共同协作完成的
–JVM依据classpath执行的类库的顺序来查找类
–潜在的问题
- 如何找到正确的类,如classpath路径的前后
- 如何避免恶意的类,如一个假的String类
- 加载的顺序,如先加载
类加载器ClassLoader
–负责查找、加载、校验字节码的应用程序
–java.lang.ClassLoader
- •load(String className) 根据名字加载一个类,返回类的实例
- •defineClass(String name, byte[] b, int off, int len) 将一个字节流定义一个类
- •findClass(String name) 查找一个类
- •findLoadedClass(String name) 在已加载的类中,查找一个类
- •成员变量ClassLoaderparent;
JVM四级类加载器(向上委托,向下加载,下可用上,上不可用下)
JVM四级类加载器严格遵循从上到下的加载机制
–启动类加载器(Bootstrap),系统类rt.jar(静态)
–扩展类加载器(Platform/Extension),jre/lib/ext(静态)
–应用类加载器(App),classpath(静态)
–用户自定义加载器(Plugin),程序自定义(动态)
•优点
–层次分明,逐级加载,确保核心类可信
–兼顾静态和动态
JVM四级类加载器的动态性
–使用虚拟机参数-Xbootclasspath,将jar或目录提高到Bootstrap等级
–使用ServiceLoader和SPI机制,实现上层加载器的类,访问下层加载器的类
–使用URLClassLoader,可以在运行时增加新的classpath路径
–使用自定义的ClassLoader,可以通过重写loadClass和findClass方法动态加载字节码,还可以在加载字节码过程中进行修改/校验等操作
类加载器双亲委托
–首先判断是否已经加载
–若无,找父加载器加载
–若再无,由当前加载器加载
Java严格执行双亲委托机制
JVM四级类加载器严格遵循从上到下的加载机制
–类会由最顶层的加载器来加载,如没有,才由下级加载器加载
–委托是单向的,确保上层核心的类的正确性
–但是上级类加载器所加载的类,无法访问下级类加载器所加载的类
- •例如,java.lang.String无法访问自定义的一个Test类
- •Java是一个遵循契约设计的程序语言,核心类库提供接口,应用层提供实现
- •核心类库是BootstrapClassLoader加载
- •应用层是AppClassLoader加载
- •典型例子是JDBC和XML Parser等
双亲委托的补充
–执行Java,添加虚拟机参数
-Xbootclasspath/a:path,将类路径配置为Bootstrap等级
- •使用java –X 查看具体的帮助
–使用ServiceLoader.load方法,来加载(底层加载器所加载的类)
- 利用ServiceLoader机制可以提供上层加载器的类来访问下层加载器的类
–以JDBC加载为例
自定义加载路径
–弥补类搜索路径静态的不足
–URLClassLoader, 从多个URL(jar或者目录)中加载类
–继承于ClassLoader
–程序运行时增加新的类加载路径
–可从多个来源中加载类
•目录
•jar包
•网络
–addURL添加路径
–close方法关闭
- •程序动态增加类加载路径,克服静态路径的缺点
- •不同程序/线程可以有不同的加载路径,互相隔离
- •重复加载某一个路径,实现程序热部署
自定义类加载器
–继承ClassLoader类
–重写findClass(String className)方法
–使用时,默认先调用loadClass(className)来查看是否已经加载过,然后委托双亲加载,如果都没有,再通过findClass加载返回
- •在findClass中,首先读取字节码文件
- •然后,调用defineClass(className, bytes, off, len) 将类注册到虚拟机中
- •可以重写loadClass方法来突破双亲加载
- 同一个类可以被不同层级的加载器加载,且作为2个类对待