欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

jvm第六节-类加载器

程序员文章站 2022-05-28 15:34:53
...

类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一。它使得 Java 类可以被动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的。Java Applet 需要从远程下载 Java 类文件到浏览器中并执行。现在类加载器在 Web 容器和 OSGi 中得到了广泛的使用。一般来说,Java 应用的开发人员不需要直接同类加载器进行交互。Java 虚拟机默认的行为就已经足够满足大多数情况的需求了。不过如果遇到了需要与类加载器进行交互的情况,而对类加载器的机制又不是很了解的话,就很容易花大量的时间去调试 ClassNotFoundException和NoClassDefFoundError等异常。本文将详细介绍 Java 的类加载器,帮助读者深刻理解 Java 语言中的这个重要概念。下面首先介绍一些相关的基本概念。
class的装载流程:加载-》连接-》初始化
加载
取得类文件的二进制流,将流转为方法区数据结构
连接
验证:验证文件格式,验证元数据(是否偶父类,是否继承了final类,继承抽象方法的非抽象类是否完全实现了抽象类的方法),字节码验证(比如不符合常量池的长度,比如接口和方法不存在)
准备:准备阶   段final修饰的会赋值,其他的会再初始化的<clinit>中设置
解析:将符号应用换成直接引用如将"java.lang.Object"换成对象对应的指针
初始化
给static变量赋值,static块赋值,<clinit>调用前保证父类<clinit>被调用,<clinit>是线程安全的.
ClassLoader是一个抽象类,他将读入java字节码将类装载到jvm中,可定制,从文件,网络加载class文件,负责类加载过程的加载阶段,连接以后是没关系的
系统中的类加载器:
classLoader默认工作模式-协同同坐,自底向上检查类是否检查,如果从底到上都没有就尝试去加载,加载的方向是反的,启动calssloader先加载,如果启动classloader没加载到,依次往下加载。
 BootStrap ClassLoader 加载  rt.jar   可以用 /-Xbootclasspath用来设置启动类加载器的读取路径
Extension ClassLoader 加载  %JAVA_HOME%/lib/etx/*jar
App ClassLoader 加载 classpaht下文件
有的接口或者工厂类是在rt.jar而实现在程序里的,但bootclassloader无法看到appclassloader里的内容,如何解决了,Thread.setContextClassloader(),通过上下文加载器可以突破双亲模式的缺陷。
下图是我通过改变 BootStrap ClassLoader 的加载路径来加载类代码如下:

jvm第六节-类加载器
            
    
    博客分类: java基础 jvm类加载器jvm热加载热加载 
 分别把相同的类放在不同的目录下,分别答应不同的类容
public class HelloClassLoader{
	public static void main(String[]args){
		System.out.println("i am in bootclassloader");
	}
}
 如图

jvm第六节-类加载器
            
    
    博客分类: java基础 jvm类加载器jvm热加载热加载 
 可以证明类加载器是从顶向下加载的
热加载
我们实际的程序在生产环境中可能要显现不能停止程序而实现更新,下面我写了一个热加载的例子

建立4个类代码分别如下:

第一个类:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class Worker {
public void doit(){
Calendar cd = Calendar.getInstance();
cd.setTime(new Date());

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:MM:ss");
String date=sdf.format(new Date());
System.out.println("hello do it==" + date);
}
}

 
 
第二个类:

 

public class MyClassLoader  extends ClassLoader {
public Class<?> findClass(byte[] b) throws ClassNotFoundException {
        return defineClass(null, b, 0, b.length);
    }
}

 
第三个类:

 

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
 * 自定义类加载
 * @Author:xuehan
 * @Date:2016年2月27日下午5:00:38
 */
public class MyclassLoaderUtils{

// 最后一次被修改时间
long lastmTime = System.currentTimeMillis();

// 判断class文件是否被修改过
public boolean isClassModified(String fileName){
File file = new File(fileName);
if(file.lastModified() - lastmTime > 0){
System.out.println("文件被修改");
lastmTime = System.currentTimeMillis();
return true;
}
return false;
}
 // 从本地读取文件
@SuppressWarnings("unused")
private byte[] getClassBytes(String filename) throws IOException {
File file = new File(filename);
long len = file.length();
lastmTime = file.lastModified();
byte raw[] = new byte[(int) len];
FileInputStream fin = new FileInputStream(file);
int r = fin.read(raw);
fin.close();
return raw;
}
//加载类, 如果类文件修改过加载,如果没有修改,返回当前的
    public Class loadClass(String name) throws ClassNotFoundException, IOException{
    Class c = null;
     if (isClassModified(name)){
        MyClassLoader mc =  new MyClassLoader();
      return c = mc.findClass(getClassBytes(name));
     }
     return c;
    }

第四个类:




import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


/**
 * 虚拟机加载入口的地方
 * @Author:xuehan
 * @Date:2016年2月27日下午5:33:14
 */
public class HelloMain {


@SuppressWarnings({ "rawtypes", "unchecked" })
public static void main(String[] args)
throws ClassNotFoundException, IOException, NoSuchMethodException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, InstantiationException, InterruptedException {
String path = "D:\\Users\\workspace\\jvm\\src\\main\\java\\com\\jvm\\day3\\Worker.class";
MyclassLoaderUtils mc = new MyclassLoaderUtils();
while (true) {
Class c = mc.loadClass(path);
if(null == c){
c = Worker.class;
}
Object o = c.newInstance();
Method m = c.getMethod("doit");
m.invoke(o);
Thread.sleep(2000);
}
}
}

jvm第六节-类加载器
            
    
    博客分类: java基础 jvm类加载器jvm热加载热加载 

 
jvm第六节-类加载器
            
    
    博客分类: java基础 jvm类加载器jvm热加载热加载 
我们动态的扫描class文件最后更新时间,确定程序是否被更新了,然后动态的加载。