如何实现热加载
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