java中的动态加载和热替换

1.C++编写的程序需要经过编译称为目标文件,然后在程序执行之前进行链接后才可以称为可以运行的可执行程序,这个链接可以发生在程序运行之前,也可以发生在程序运行后(在内核中完成链接过程)再被执行。(运行可以理解为双击打开)。而Java则只需要编译成字节码,然后交给JVM解析器去链接执行就可以了。(C++系列也拥有动态加载和动态链接等概念)

2.Java的动态加载实际上就是程序在执行过程中可以根据程序设定去加载需要被执行的字节码文件。

3.热替换属于动态加载的一种,但是热替换是特殊的动态加载机制。

4.动态加载在Java中有2种实现,第一种通过ClassLoader.loadClass()去加载,ClassLoader最高级别的类加载器,所有的类都归他管理,用loadClass加载的类,是未经过初始化的,所以很多静态变量和方法无法被使用,第二种方法则是,Class.forName().用这个方法加载的类已经经过初始化。

5.而如何实现热替换呢?首先我们要知道ClassLoader中的loadClass在加载类的时候会检测该类是否已经存在,如果存在则不会去加载,如果不存在则加载该类并缓存。所以默认的ClassLoader是无法实现热替换的。换句话说,要实现热替换就必须实现一个自己的MyClassLoader,实现一个自己的用于加载类的方法findClass(),在方法里面要做的事情就是读取本地字节码文件,只用父类的defineClass()方法去解析它。这样就可以获取新的类了,而旧的类由于ClassLoader不可达,所以会被GC回收。

下面是MyClassLoader的代码:

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class MyClassLoader extends ClassLoader {
    public MyClassLoader() {
    }

    public Class<?> findClass(String name) throws ClassNotFoundException {
        String classPath = MyClassLoader.class.getResource("/").getPath();
        String fileName = name.replace(".", "/") + ".class";
        File classFile = new File(classPath, fileName);
        if(!classFile.exists()) {
            throw new ClassNotFoundException(classFile.getPath() + " 不存在");
        } else {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ByteBuffer bf = ByteBuffer.allocate(1024);
            FileInputStream fis = null;
            FileChannel fc = null;

            try {
                fis = new FileInputStream(classFile);
                fc = fis.getChannel();

                while(fc.read(bf) > 0) {
                    bf.flip();
                    bos.write(bf.array(), 0, bf.limit());
                    bf.clear();
                }
            } catch (FileNotFoundException var20) {
                var20.printStackTrace();
            } catch (IOException var21) {
                var21.printStackTrace();
            } finally {
                try {
                    fis.close();
                    fc.close();
                } catch (IOException var19) {
                    var19.printStackTrace();
                }

            }

            return this.defineClass(bos.toByteArray(), 0, bos.toByteArray().length);
        }
    }
}

发表评论