一、class装载验证流程
1、加载
> 装载类的第一个阶段
> 取得类的二进制流
> 转为方法区数据结构
> 在Java堆中生成对应的java.lang.Class对象
2、链接
> 验证
目的:保证Class流的格式是正确的
文件格式的验证
是否以0xCAFEBABE开头
版本号是否合理
元数据验证
是否有父类
继承了final类?
非抽象类实现了所有的抽象方法
字节码验证 (很复杂)
运行检查
栈数据类型和操作码数据参数吻合
跳转指令指定到合理的位置
符号引用验证
常量池中描述类是否存在
访问的方法或字段是否存在且有足够的权限
注:不加标识符,默认包内访问
> 准备
分配内存,并为类设置初始值 (方法区中)
public static int v=1;
在准备阶段中,v会被设置为0
在初始化的<clinit>中才会被设置为1
对于static final类型,在准备阶段就会被赋上正确的值
public static final int v=1;
> 解析
3、初始化
> 执行类构造器<clinit>
static变量 赋值语句
static{}语句
> 子类的<clinit>调用前保证父类的<clinit>被调用
> <clinit>是线程安全的
二、什么是类装载器ClassLoader
1、ClassLoader是一个抽象类
2、ClassLoader的实例将读入Java字节码将类装载到JVM中
3、ClassLoader可以定制,满足不同的字节码流获取方式
4、ClassLoader负责类装载过程中的加载阶段
三、JDK中ClassLoader默认设计模式
1、ClassLoader的重要方法
public Class<?> loadClass(String name) throws ClassNotFoundException
方法描述:载入并返回一个Class
protected final Class<?> defineClass(byte[] b, int off, int len)
方法描述:定义一个类,不公开调用
protected Class<?> findClass(String name) throws ClassNotFoundException
方法描述:loadClass回调该方法,自定义ClassLoader的推荐做法
protected final Class<?> findLoadedClass(String name)
方法描述:寻找已经加载的类
2、分类
BootStrap ClassLoader (启动ClassLoader)
Extension ClassLoader (扩展ClassLoader)
App ClassLoader (应用ClassLoader/系统ClassLoader)
Custom ClassLoader(自定义ClassLoader)
每个ClassLoader都有一个Parent作为父亲
说明:类加载是从顶向下的
3、强制在apploader中加载
在查找类的时候,先在底层的Loader查找,是从下往上的。Apploader能找到,就不会去上层加载器加载。
public static void main(String args[]) throws Exception {
ClassLoader cl=FindClassOrder2.class.getClassLoader();
byte[] bHelloLoader=loadClassBytes("geym.jvm.ch6.findorder.HelloLoader");
Method md_defineClass=ClassLoader.class.getDeclaredMethod("defineClass", byte[].class,int.class,int.class);
md_defineClass.setAccessible(true);
md_defineClass.invoke(cl, bHelloLoader,0,bHelloLoader.length);
md_defineClass.setAccessible(false);
HelloLoader loader = new HelloLoader();
System.out.println(loader.getClass().getClassLoader());
loader.print();
}
-Xbootclasspath/a:D:/tmp/clz
4、问题
问题:BootClassLoader如何访问ExtClassLoader/AppClassLoader底层的类?
解决:Thread. setContextClassLoader()
上下文加载器
是一个角色
用以解决顶层ClassLoader无法访问底层ClassLoader的类的问题
基本思想是,在顶层ClassLoader中,传入底层ClassLoader的实例
5、双亲模式的破坏
双亲模式是默认的模式,但不是必须这么做。
Tomcat的WebappClassLoader 就会先加载自己的Class,找不到再委托parent(模式破坏,应该是自顶向下加载) 。
OSGi的ClassLoader形成网状结构,根据需要自由加载Class(模块化热加载:一会Class进来,一会又离开,传统Parent加载模式不适用,加载机制很复杂)。
四、打破常规模式
jdk的ClassLoader未强制使用其parent双亲模式,可以重载ClassLoader,例如破坏jdk的ClassLoader双亲模式的产物:
1、tomcat中Webapp的ClassLoader先加载自己的;
2、OSGI热部署,网状结构访问模式(让程序有多种可能性,使程序架构更加灵活,有无限的想象空间)。
五、热替换
含义: 当一个class被替换后,系统无需重启,替换的类立即生效。