美文网首页Java 杂谈
ClassLoader实战一、ClassLoader实现热部署

ClassLoader实战一、ClassLoader实现热部署

作者: 编程界的小学生 | 来源:发表于2017-08-28 16:28 被阅读409次

一、思路

利用自己的类加载器去重新加载class文件

二、说明
不多说废话,直接上代码,有不懂的地方可以留言也可以私信我

三、代码

(1)被监听(需要热部署)的类

public interface Message {
    void send();
}
public class MessageImpl implements Message {

    @Override
    public void send() {
        System.out.println("发送消息AAAA");
    }
}

(2)自定义类加载器

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class MyClassLoader extends ClassLoader {
    //类加载器名称
    private String name;
    //类加载路径
    private String path;
    
    public MyClassLoader(ClassLoader parent, String name, String path) {
        super(parent); //父类加载器
        this.name = name;
        this.path = path;
    }
    /**
     * 重写父类的loadClass方法
     */
    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        Class<?> clazz = null;
        //判断是不是本类
        if(this.name.equals(name)) {
            //查找是否已经被加载过了
            clazz = this.findLoadedClass(name);
            if(clazz == null) {
                //如果没找到则继续去查找
                clazz = this.findClass(name);
            }
        }
        return super.loadClass(name);
    }

    /**
     * 重写findClass方法,自定义规则
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        //转成二进制字节流,因为JVM只认识二进制不认识字符串
        byte[] b = readFileToByteArray(name);
        return this.defineClass(this.name, b, 0, b.length);
    }

    /**
     * 将包名转换成全路径名,比如
     * 
     * temp.a.com.dn.Demo -> D:/temp/a/com/dn/Demo.class
     * 
     * @param name
     * @return
     */
    private byte[] readFileToByteArray(String name) {
        InputStream is = null;
        byte[] rtnData = null;
        //转换
        name = name.replaceAll("\\.", "/");
        //拼接
        String filePath = this.path + name + ".class";
        File file = new File(filePath);
        
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        
        try {
            is = new FileInputStream(file);
            int tmp = 0;
            while((tmp = is.read()) != -1) {
                os.write(tmp);
            }
            
            rtnData = os.toByteArray();
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(null != os) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return rtnData;
    }
    
    public Class<?> loadClass() throws ClassNotFoundException {
        return loadClass(this.name);
    }
    
}

(3)main方法

public class TestClassLoader {
    //需要热部署的那个类的全路径名称,不一定必须在项目中,可以在任意位置
    private static final String name = "jvm.dongnao.demo2.MessageImpl";
    //需要热部署的类的classes目录
    private static final String path = "C:\\Users\\Chen\\workspace\\effect-java\\target\\classes\\";
    
    public static void main(String[] args) throws Exception {
        Message message = null;
        
        while(true) {
            //1、实例化自己的类加载器,并将当前线程的类加载器作为父类加载器,并将name和path传进去
            MyClassLoader loader = new MyClassLoader(Thread.currentThread().getContextClassLoader(), name, path);
            //2、调用本来的loadClass方法
            Class<?> clazz = loader.loadClass();
            //实例化上面path+name+".class"
            message = (Message)clazz.newInstance();
            //调用方法
            message.send();
            //每隔3s执行一次,检查class是否有变化
            Thread.sleep(3000);
        }
    }
}

三、结果
直接运行main方法,然后将MessageImpl的send方法输出改成BBB查看效果

发送消息AAAA
发送消息AAAA
发送消息BBBB
发送消息BBBB

四、强调

本章内容好多代码都可以优化,比如转成byte可以用nio,关闭流可以用Apache工具集优雅的关闭等等。
不难发现我写了个死循环,并不管类有没有变化都去重新加载它,这样做法是不好的,可以用Apache vfs去监听他。

我写这篇文章的目的是为了说明原理,而不是当工具来用,写的太复杂大家理解起来也不容易。若有任何疑问都可以留言也可以私信我。

若有兴趣,欢迎来加入群,【Java初学者学习交流群】:458430385,此群有Java开发人员、UI设计人员和前端工程师。有问必答,共同探讨学习,一起进步!
欢迎关注我的微信公众号【Java码农社区】,会定时推送各种干货:


qrcode_for_gh_577b64e73701_258.jpg

相关文章

网友评论

    本文标题:ClassLoader实战一、ClassLoader实现热部署

    本文链接:https://www.haomeiwen.com/subject/ehdgdxtx.html