如何做到模块热部署

热部署其实就是如何在服务器不重启的时候动态的替换相关模块,要讲热部署之前就要先了解一下类加载机制。

JVM加载一个类需要经过这么几个阶段,加载,验证,解析,初始化,使用,卸载。其中到初始化阶段之前是类的加载全部。并且JVM在加载一个类时是用的双亲委派模型。也就是当classloader加载一个类的时候并不是自己去尝试加载,而是一层一层委派,当顶层父加载器无法加载,再自顶向下尝试加载。

200757_mEs3_3203060.png

类加载器在加载一个类时,只会加载一次,也就是一个加载器下的同名类只会存在一个,每次加载都会先看缓存。所以热部署的关键就是自定义一个加载器,先继承classloader,然后实现findclass方法,这样就能绕过双亲委派模型的限制。

直接上代码:每次加载一个类的时候先看一下是否被修改过,如果被修改过那么尝试加载。

这里有个问题,类加载器啥时候被回收,好像看起来会一直占着不会被GC。所以现在基本上都是通过OSGi框架来实现模块的热插拔,感兴趣的朋友可以参考《OSGi原理与最佳实践》。

package com.dlb.note.hotDeploy;

import java.lang.reflect.Method;

/**
 * 功能:主函数类,专门用于测试
 * 版本:1.0
 * 日期:2016/12/9 11:18
 * 作者:馟苏
 */
public class Main {
    /**
     * 主函数
     */
    public static void main(String []args) {
        while (true) {
            try {
                Class cls = ManageClassLoader.loadClass("E:\\note\\target\\classes\\com\\dlb\\note\\doj\\Cat.class");
                Method method = cls.getMethod("cry");
                method.invoke(cls.newInstance());

                Thread.sleep(5000);
            } catch (Exception e) {
                System.out.println(e);
            }
        }
    }
}
package com.dlb.note.hotDeploy;

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

/**
 * 功能:管理类加载器
 * 版本:1.0
 * 日期:2016/12/9 10:34
 * 作者:馟苏
 */
public class ManageClassLoader {
    /**类文件的上次修改时间*/
    private static Long lastModified = 0l;
    /**类的缓存*/
    private static Class cache = null;
    /**动态类加载器*/
    private static DynamicClassLoader dc = null;

    /**
     * 这是入口方法!
     * 加载类, 如果类文件修改过加载,如果没有修改,返回当前的
     * @param fileName 路径名 + 文件名 + 扩展名
     * @return
     * @throws ClassNotFoundException
     * @throws IOException
     */
    public synchronized static Class loadClass(String fileName) throws ClassNotFoundException, IOException{
        if (isClassModified(fileName)){ // 类文件被修改
            /**创建一个动态类加载器用于加载类(同一个类加载器下不能出现两个同名类)*/
            dc =  new DynamicClassLoader();
            return (cache = dc.findClass(getBytes(fileName)));
        }

        return cache;
    }

    /**
     * 判断是否被修改过
     * @param fileName 路径名 + 文件名 + 扩展名
     * @return
     */
    private synchronized static boolean isClassModified(String fileName) {
        boolean returnValue = false;

        File file = new File(fileName);

        if (file.lastModified() > lastModified) {
            returnValue = true;
        }

        return returnValue;
    }

    /**
     * 从本地读取文件
     * @param fileName 路径名 + 文件名 + 扩展名
     * @return
     * @throws IOException
     */
    private synchronized static byte[] getBytes(String fileName) throws IOException {
        File file = new File(fileName);
        long len = file.length();
        lastModified = file.lastModified(); // 文件上次修改时间

        byte raw[] = new byte[(int) len];

        FileInputStream fin = new FileInputStream(file);
        int r = fin.read(raw);

        if (r != len) {
            throw new IOException("Can't read all, " + r + " != " + len);
        }

        fin.close();

        return raw;
    }

    public static void main(String []args) throws Exception{
        DynamicClassLoader dc =  new DynamicClassLoader();
        Class<?> cls = dc.findClass(getBytes("E:\\note\\target\\classes\\com\\dlb\\note\\doj\\Cat.class"));
        System.out.println(cls);

        cls = dc.findClass(getBytes("E:\\note\\target\\classes\\com\\dlb\\note\\doj\\Cat.class"));
        System.out.println(cls);
    }
}

/**
 * 一个动态类加载器,用于加载类(同一个类加载器下不能出现两个同名类)
 */
class DynamicClassLoader extends ClassLoader {
    /**
     * 根据字节定义类
     * 注意:对于用一个类加载器不能定义同一个类名两次
     * @param b
     * @return
     * @throws ClassNotFoundException
     */
    public Class<?> findClass(byte[] b) throws ClassNotFoundException {
        return defineClass(null, b, 0, b.length);
    }
}

转载于:https://my.oschina.net/u/3203060/blog/852955

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值