• 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

  • 相关阅读:
    share point 已在此服务器场中安装 ID 为 15/b7a69889-1789-4855-b8bd-9a3b4cfd7fc0 的功能。请使用强制属性显式地重新安装此功能。
    给一个div添加多个背景图片
    input输入框,在手机上,软键盘会将固定定位和绝对定位的按钮顶起,解决办法
    js判断浏览器,设备类型
    js中函数function的三种定义方式,声明式定义函数、函数表达式、立即执行函数的区别
    vue项目里面,__ob__对象的理解
    浏览器渲染过程-面试
    MySQL的连接查询:left join , right join , join
    MYSQL实现连表查询
    node后台koa2项目,如何发布到服务器?入门学习
  • 原文地址:https://www.cnblogs.com/princessd8251/p/3967591.html
Copyright © 2020-2023  润新知