Java实现热替换
package test;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
public class DynamicLoader extends ClassLoader {
private String baseDir;
public DynamicLoader(String baseDir) {
super();
this.baseDir = baseDir;
}
private String getClassFile(String className){
return baseDir+className.replace(".", "/")+".class";
}
protected Class findClass(String className) throws ClassNotFoundException {
Class clazz = this.findLoadedClass(className);
if (null == clazz) {
try {
String classFile = getClassFile(className);
FileInputStream fis = new FileInputStream(classFile);
FileChannel fileC = fis.getChannel();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
WritableByteChannel outC = Channels.newChannel(baos);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
int count = 0;
while ((count = fileC.read(buffer)) > 0) {
buffer.flip();
outC.write(buffer);
buffer.clear();
}
fis.close();
byte[] bytes = baos.toByteArray();
clazz = defineClass(className, bytes, 0, bytes.length);
} catch (Exception e) {
System.out.println("can not load class "+className +" from DynamicLoader.");
}
}
return clazz;
}
protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
// First, check if the class has already been loaded
Class re=findClass(name);
if(re==null){
return super.loadClass(name,resolve);
}
return re;
}
}
package test;
public class Worker {
public void doit(){
System.out.println("I am version 3");
}
}
package test;
import java.lang.reflect.Method;
public class HelloMain {
public static void main(String[] args) throws Exception {
while(true)
{
DynamicLoader loader = new DynamicLoader("F:\\workspace\\HibernateSrc\\bin\\");
Class clazz = loader.loadClass("test.Worker");
Object instance = clazz.newInstance();
Method doit = clazz.getDeclaredMethod("doit",null);
doit.invoke(instance, null);
Thread.sleep(2000);
}
}
}
思路:
在HelloMain里面定时的创建新的自定义ClassLoader,然后指定加载某个目录的class文件.加载的时候不是父类优先,而是子类优先模式.
自定义的ClassLoader找到Worker类后,反射穿件实例.
这里不能用new关键字在HelloMain类里面创建Worker实例,也能让反射生成的实例转型成Worker类型,因为那样会导致AppliationClassLoader加载Worker类.
如果被AppliationClassLoader加载了Worker类,那么新版本的Worker就不能再被Application ClassLoader加载了,一个ClassLoader里面同名的class只能有一个.
如果这个时候让AppliationClassLoader加载了老的Worker类,在替换的时候让自定义ClassLoader加载新版本的Woker类,则会出现ClassCastException.
因为这些Worker类来之不同的ClassLoader,比如下面代码会报ClassCastException.
DynamicLoader loader = new DynamicLoader("F:workspaceHibernateSrcbin");
Class clazz = loader.loadClass("test.Worker");
Worker instance = (Worker)clazz.newInstance();//ClassCastException error
instance.doit();
所以Worker类只能是让自定义的ClassLoader加载.同时下次要运行的时候,也要在创建一个新的自定义ClassLoader来加载.
参考 http://www.cnblogs.com/princessd8251/articles/3967569.html