如何实现热加载

2017-09-15  本文已影响0人  zychen143

运行一个程序HelloMain,他会循环调用另外一个类Worker.doit()方法。此时,对Worker.doit()方法做更新。要求 更新后,HelloMain可以发现新的版本。 可以选择替换class文件 ,也可以选择替换jar包。

答:我在这里选择的是替换class. 这题的关键是发现class文件改变,用新的classloader去加载class文件,然后程序调用的也是通过新加载的class去调用。 由于Java有双亲委派模式加哉,故需要热部署的class必须通过自定义的classloader去加载。 强调同一个类的概念:1.类加载器负责加载所有的类,系统为所有被载入内存中的类生成一个java.lang.Class实例.一旦一个类被载入JVM中,同一个类就不会被再次载入了。2.在Java中,一个类用其全限定类名,包名和类名,作为标识;但在JVM中一个类用其全限定类名和其类加载器作为其唯一标识。 即,如果Worker被appclassloader加载过后,又被自定义classloader加载,它们两个不是同一个class.所以在我的程序中,Worker不能被appclassloader,即在我的程序中不能明确使用“Worker.doit()”。这里我是通过反射调用的,

package leetcode.classLoad;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * @Author: 章源辰
 * @Date: 2017/9/15
 * @Description:
 */
public class HelloMain {
    private URLClassLoader classLoader;
    private long lastTime;
    private Object worker;
    private String classDir="D:\\mywork\\aaa\\target\\classes\\";

    public static void main(String[] args) throws Exception{
        HelloMain helloMain = new HelloMain();
        helloMain.execute();
    }

    private void execute() throws Exception{
        while (true){
            if (checkIsNeedReload()){
                System.out.println("检测到新版本,准备重新加载");
                reload();
                System.out.println("重新加载完成");
            }
            invokeMethod();
            Thread.sleep(1000);
        }
    }

    private void invokeMethod() throws Exception{
        Method method = worker.getClass().getDeclaredMethod("doit", null);
        method.invoke(worker, null);
    }

    private void reload() throws  Exception{
        classLoader = new MyClassLoader(new URL[]{
                new URL("file:"+classDir)
        });
        worker = classLoader.loadClass("leetcode.classLoad.Worker").newInstance();
    }

    private boolean checkIsNeedReload() {
        File file = new File(classDir+"leetcode\\classLoad\\Worker.class");
        long newTime = file.lastModified();
        if (newTime > lastTime){
            lastTime = newTime;
            return true;
        }else {
            return false;
        }
    }
}

package leetcode.classLoad;

/**
 * @Author: 章源辰
 * @Date: 2017/9/15
 * @Description:
 */
public class Worker {

    public void doit(){
        System.out.println("调用work中的doit方法aaaaaa=======");
    }
}

package leetcode.classLoad;

import java.net.URL;
import java.net.URLClassLoader;

/**
 * @Author: 章源辰
 * @Date: 2017/9/15
 * @Description:
 */
public class MyClassLoader extends URLClassLoader {

    public MyClassLoader(URL[] urls) {
        super(urls);
    }

    @Override
    protected synchronized Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException {
        Class c = findLoadedClass(name);
        if (c == null) {
            try {
                c = findClass(name);
            } catch (Exception e) {
            }
        }
        if (c == null) {
            c = super.loadClass(name, resolve);
        }
        return c;
    }

}

image.png
上一篇下一篇

猜你喜欢

热点阅读