java逻辑代码热更新机制

在之前的一个游戏项目中,将游戏的逻辑部分和下层的数据持久化部分分开写,建立两个项目,上层的逻辑依赖下层

<dependency>
    <groupId>com.yp</groupId>
    <artifactId>common</artifactId>
    <version>1.0</version>
</dependency>

<dependency>
    <groupId>com.yp</groupId>
    <artifactId>game</artifactId>
    <version>final</version>
</dependency>

在game项目作为启动项目的入口,logic项目打包成jar包,然后通过自定义类加载器来热加载logic.jar包

自定义的HotSwapLoader继承了ClassLoader 类并重写了findClass方法

private void loadLogicJar() {
    String path = getLogicPath() + getLogicJar();

    try {
        hotswapcl = new HotSwapLoader(path);
        HotSwap.setLoader(hotswapcl);
        hotswapcl.load((classes, jar) -> postLoadClass(classes, jar));
    } catch (Exception ex) {
        LOG.error("loadlogicjar", "load class error: " + ex.getMessage());
    }

}
private void postLoadClass(@SuppressWarnings("rawtypes") Set<Class> clzs, JarFile jar) {

    if (onLoadJar(clzs, jar)) {

        ManifestUtil m = new ManifestUtil(jar);
        hotver.gitcommit = m.getValue("git-commit");
        LOG.info("manifest", "hot git-commit=" + hotver.gitcommit);
        
        onLoadJarFinish(clzs, jar);

        //switch to new
        HotSwap.wlock();
        try {
            onHotSwap();
            HotSwap.swapLoader();
        } finally {
            HotSwap.wUnlock();
        }
        
    }
}
public boolean onLoadJar(@SuppressWarnings("rawtypes") Set<Class> clzs, JarFile jar) {

    tableloader = new TableLoader(jar, "tables");
    try {

        for (Class<?> c : clzs) {
            if (WSControllerBase.class.isAssignableFrom(c)) {
                wsserver.registerController(c);
            } else if (HttpControllerBase.class.isAssignableFrom(c)) {
                httpserver.registerController(c);
            } else if (c.getName().startsWith("tables.")) {
                //load tables
               if (!c.getName().contains("$")) {
                  tableloader.addTable(c);
               }
            } else if (IGameListener.class.isAssignableFrom(c)) {
                temp = (IGameListener) c.newInstance();
            } else {
                LOG.debug("loadclass", "load normal class: " + c.getName());
            }
        }

        tableloader.releaseJar();

        return true;
    } catch (Exception ex) {
        LOG.error("loadclass", "load class error: " + ex.getMessage());
        return false;
    }
}
public class HotSwapLoader extends ClassLoader {
    public void load(@SuppressWarnings("rawtypes") BiConsumer<Set<Class>, JarFile> postLoad) throws Exception {

        Enumeration<JarEntry> entries = jf.entries();

        @SuppressWarnings("rawtypes")
      Set<Class> set = new HashSet<>();

        LOG.info("loadclass", "loading class now ......");
        
        while (entries.hasMoreElements()) {

            JarEntry entry = entries.nextElement();

            String name = entry.getName();

            LOG.debug("loadclass", "begin load: " + name);

            if (name.endsWith(".class")) {
                String clzname = name.substring(0, name.length() - 6).replace('/', '.');

                Class<?> c = loadClass(clzname);

                set.add(c);
            }

        }

        if (postLoad != null) {
            LOG.info("loadclass", "begin post load");
            postLoad.accept(set, jf);
            LOG.info("loadclass", "end post load");
        }
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String entryname = name.replace('.', '/') + ".class";
        JarEntry entry = jf.getJarEntry(entryname);
        if (entry == null) {
            throw new ClassNotFoundException("can not find class: " + name);
        }

        byte[] raw;
        try (InputStream stream = jf.getInputStream(entry)) {
            raw = readStream(stream);
        } catch (IOException ex) {
            throw new ClassNotFoundException("read class error: " + name);
        }

        Class<?> c = defineClass(name, raw, 0, raw.length);

        return c;

    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃肉的鱼儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值