自定义类加载器实现代码热替换

本文介绍了一种在不重启服务器的情况下,通过自定义类加载器实现代码热替换的方法。通过修改类的代码并立即生效,避免了因代码更新而重启服务器带来的服务中断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码热替换,在不重启服务器的情况下可以修改类的代码并使之生效

1. 自定义类加载器

package com.pibgstar.demo.java;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Set;

/**
 * @author pibigstar
 * @desc 代码热替换,在不重启服务器的情况下可以修改类的代码并使之生效
 **/
public class MyClassLoader extends ClassLoader{
    // 定义.class路径
    private String swapPath;
    // 存储哪些类需要我自身去加载
    private Set<String> myselfLoader;

    public MyClassLoader(String swapPath, Set<String> myselfLoader) {
        this.swapPath = swapPath;
        this.myselfLoader = myselfLoader;
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        Class<?> loadedClass = findLoadedClass(name);
        // 需要我自己去加载
        if (loadedClass==null && myselfLoader.contains(name)) {
            loadedClass = findClass(name);
            if (loadedClass!=null){
                return loadedClass;
            }
        }
        return super.loadClass(name, resolve);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // 根据文件系统路径加载class文件,并返回byte数组
        byte[] b = getClassByte(name);
        // 调用ClassLoader提供的方法,将二进制数组转换成Class类的实例
        return defineClass(name,b,0,b.length);
    }

    private byte[] getClassByte(String name) {
        String className = name.substring(name.lastIndexOf(".")+1,
        				name.length()) + ".class";
        try {
            FileInputStream fis = new FileInputStream(swapPath + className);

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buff = new byte[1024];
            int length = 0;
            while ((length=fis.read(buff))>0){
                baos.write(buff,0,length);
            }
            return baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new byte[]{};
    }
}

2. 测试

自定义一个每2秒打印调用一次方法打印版本号,先编译一次版本号为2的 MyClassLoaderTest .class类,然后启动版本号为1的,在运行过程中,我们把版本号为1的MyClassLoaderTest .class类替换成版本号为2的MyClassLoaderTest .class类,我们发现控制台立马输出了版本号2

package com.pibgstar.demo.java;
import com.google.common.collect.Sets;
import java.util.Timer;
import java.util.TimerTask;
/**
 * @author pibigstar
 * @desc
 **/
public class MyClassLoaderTest {
    public void printVersion() {
        System.out.println("版本号1");
    }
    public static void main(String[] args){
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                // target/classes/com/pibgstar/demo/java/swap/
                String swapPath = MyClassLoader.class.getResource("").getPath();
                String className = "com.pibgstar.demo.java.MyClassLoaderTest";
				// 创建自定义的类加载器,将路径和需要我们自己去加载的类名传递进去
                MyClassLoader myClassLoader = new MyClassLoader(swapPath, Sets.newHashSet(className));
                try {
                    //使用自定义的ClassLoader加载类,并调用printVersion方法。
                    Object o = myClassLoader.loadClass(className).newInstance();
                    o.getClass().getMethod("printVersion").invoke(o);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },0,2000);
    }
}

3. 结果截图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值