其他分享
首页 > 其他分享> > 从类加载机制到热加载

从类加载机制到热加载

作者:互联网

从类加载机制到热加载

类是如何加载的

一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)七个阶段,其中验证、准备、解析三个部分统称为连接(Linking)

加载

验证
确保Class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。

准备
​ 正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值

解析
​ Java虚拟机将常量池内的符号引用替换为直接引用的过程

初始化
- 对static修饰的变量初始化
- 如果初始化时父类没初始化 初始化父类
- 执行静态代码块

在验证、准备、解析、初始化我们能介入的空间不多,想实现热加载这个阶段只能在加载这步想办法

ClassLoader

类都是由ClassLoader进行加载的,这里先介绍最重要的双亲委派机制

启动类加载器负责加载<JAVA_HOME>\lib目录下的类或者被-Xbootclasspath参数所指定的路径中存放的,而且必须是Jave虚拟机能够识别的(及即使自己新建一个类在\lib目录下也不会被加载)

扩展类加载器加载<JAVA_HOM E>\lib\ext目录下的类

启动类加载器则是加载我们自己(ClassPath)写的类

在加载类时不本身类不会自己先加载而是由自己的父类加载器去加载

注意:这里不是继承的关系而不是组合的关系。

具体的代码在sun.misc.Launcher类中

当加载时调用java.lang.ClassLoader#loadClass(java.lang.String, boolean)方法对类进行加载

实现热加载

首先我们要知道类是否相同除了class必须相同类加载器也需要相同才为会认为两个类是相同的,并且我们需要打破双亲委派机制如果让父加载器先加载,当修改class后父类加载器是不会重新加载的

那我们新建一个自己的classLoader

public class MyClassLoader extends ClassLoader {

    private String classPath;

    public MyClassLoader(String classPath) {
        //父类构造方法 会把这个类的父加载器设置为getSystemClassLoader()也就是应用类加载器
        super();
        this.classPath = classPath;
    }
	  //把类文件转换为数组
    private byte[] loadByte(String name) throws IOException {
        name = name.replaceAll("\\.", "/");
        FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class");
        byte[] data = new byte[fis.available()];
        fis.read(data);
        fis.close();
        return data;
    }
    //loadClass会调用此方法获取class
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte[] bytes = loadByte(name);
            return defineClass(name,bytes,0,bytes.length);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ClassNotFoundException();
        }
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                long t1 = System.nanoTime();
                // 只加载自己写的类对于其他类还由父类进行加载,否则会报错
                if(!name.startsWith("ingxx")){
                    c = this.getParent().loadClass(name);
                }else {
                    c = findClass(name);
                }
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
}	

Main方法

 public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, InterruptedException {
        while (true) {
            MyClassLoader myClassLoader = new MyClassLoader("/Users/wjk/test/");
            Class<?> aClass = myClassLoader.loadClass("ingxx.user.User");
            Object o = aClass.newInstance();
            Method method1 = aClass.getMethod("sout", null);
            method1.invoke(o, null);
            Thread.sleep(5000);
        }
    }

新建一个测试类

public class User {

    public void sout(){
        System.out.println("我是李四");
    }
}

编译后把class文件放到/Users/wjk/test/ingxx/user目录下

启动后打印"我是李四" 把User类的"我是李四"改为"我是张三"放到/Users/wjk/test/ingxx/user目录下 打印结果如下

如果用同一个类加载器重复加载会抛异常如下图所示

新建类加载器在实际中的应用

Tomcat

不难想象在tomcat中我们每个war包可能有相同的类。

例如我们有两个war包一个war包依赖的Spring是4.0另一个war包以来的是5.0,如果Tomcat都使用应用类加载器加载,那么到底加载的是哪个版本呢?为了结局这个问题Tomcat自定义了一些类加载器

真对每个webApp都有自己的类加载器从而实现了类隔离

jsp类加载器针对每个jsp文件生成一个类加载器 当jsp类更改时会new一个新的jsp类加载器对jsp进行重新加载

依赖冲突

在阿里内部有一个潘多拉可以实现类隔离,保证第三方包和第二方包存在同样的类但是版本不同时也不会发生java.lang.ClassNotFoundException

标签:name,Tomcat,class,String,从类,机制,Class,加载
来源: https://www.cnblogs.com/ingxx/p/15928198.html