固定套路如下:

1. extends classloader 或者其他classloader实现

2. 重写如下父类方法:

Class findClass(String name)

3. 在步骤2中,读取.class的二进制文件数据,然后调用父类中的defineClass方法还原出Class对象。

 

实战实例:

public class SepClassLoader extends ClassLoader {


    /**
     * 需要该类加载器直接加载的类文件的基目录
     */
    private String baseDir;

    /**
     * 需要由该类加载器直接加载的类名
     */
    private HashSet classSet;

    /**
     * 带参构造
     * @param baseDir
     * @param classes
     * @throws IOException
     */
    public SepClassLoader(String baseDir, String[] classes) throws IOException {
        //TODO 存疑,实际上我这里改成super()也能很好的运行
        super(null);
        this.baseDir = baseDir;
        this.classSet = new HashSet();
        for (int i = 0; i < classes.length; i++) {
            findClass(classes[i]);
            classSet.add(classes[i]);
        }
    }

    /**
     * 重写findclass方法
     * <p>
     * 在ClassLoader中,loadClass方法先从缓存中找,缓存中没有,会代理给父类查找,如果父类中也找不到,就会调用此用户实现的findClass方法
     *
     * @param name
     * @return
     */
    @Override
    protected Class findClass(String name) {
        Class clazz = null;
        StringBuffer stringBuffer = new StringBuffer(baseDir);
        String className = name.replace('.', File.separatorChar) + ".class";
        stringBuffer.append(File.separator + className);
        File classF = new File(stringBuffer.toString());
        try {
            clazz = defineClass(name, new FileInputStream(classF), classF.length());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return clazz;
    }

    /**
     * 从二进制中还原出Class对象
     *
     * @param name
     * @param fin
     * @param len
     * @return
     * @throws IOException
     */privateClassdefineClass(String name,InputStream fin,long len)throwsIOException{byte[] raw =newbyte[(int) len];
        fin.read(raw);
        fin.close();returnsuper.defineClass(name, raw,0, raw.length);}}

使用方式:

 /**
     * ClassLoader用来加载class类文件的,实现类的热替换
     * 注意,需要在swap目录下,一层层建立目录com/tw/client/,然后将Foo.class放进去
     * @throws Exception
     */
    public static void runBy1() throws Exception {
        SepClassLoader customClassLoader = new SepClassLoader("swap", new String[]{"com.tw.client.Foo"});
        Class clazz = customClassLoader.loadClass("com.tw.client.Foo");
        Object foo = clazz.newInstance();
        Method method = foo.getClass().getMethod("sayHello", new Class[]{});
        method.invoke(foo, new Object[]{});
    }

 

posted on 2023-02-08 14:41  程序诗人  阅读(39)  评论(0编辑  收藏  举报