java热替换 classloader

来源:互联网 发布:免费库存记账软件 编辑:程序博客网 时间:2024/06/05 19:39

Java实现热替换

原文链接:http://www.cnblogs.com/princessd8251/p/3967591.html
复制代码
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

0 0