I'm Shendi
这几天要实现热更,需要自定义类加载器
也就是让一个类继承 ClassLoader
class SKClassLoader extends ClassLoader {
}
然后可以使用ClassLoader的一些 protected 修饰的方法
比如我最常用的 defineClass
- defineClass 可以将字节转换成类
在一开始,我直接使用的defineClass来实现热更,因为一个类加载器对象只能加载一次类,所以每次获取同样的类的时候需要重新new一下对象
代码如下,使用到了自己写的一些工具
class SKClassLoader extends ClassLoader {
public static Class<?> reloadClass(String clazz) throws ClassNotFoundException {
if (clazz == null) return null;
else {
sk = new SKClassLoader();
clazz = "/".concat(clazz.replace('.', '/').concat(ShendiKitInfo.CLASS_SUFFIX));
byte[] classData = null;
try (InputStream input = SKClassLoader.class.getResourceAsStream(clazz)) {
classData = new byte[input.available()];
input.read(classData, 0, classData.length);
} catch (IOException e) {
Log.printErr("重新加载指定类获取出错: " + clazz + "---" + e.getMessage());
return null;
}
return sk.defineClass(null, classData, 0, classData.length);
}
}
}
大概内容就是读取对应class文件成字节流,然后使用defineClass将字节流变为类
这个时候已经可以进行热更
于是我将项目push到了github
然后我写web项目的时候使用到这个类加载器就发现问题了
在普通java项目中可以进行热更,在web项目中不能进行热更
于是我想到了双亲加载机制,以为是父加载器将类加载了,所以子类重新获取的是父类加载的那个类
接着进行了一堆操作,测试了很多次(对ClassLoader使用还是不太熟练)
比如直接使用loadClass方法进行加载类,直接使用findClass加载类
期间错误一大把,解决了一个又出一个....
印象最深刻的是 ClassNotDefFoundException
...
后来通过查阅,在自定义类加载器中实现了 findClass 方法
代码如下
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> c = findLoadedClass(name);
if (c == null) {
sk = new SKClassLoader();
name = "/".concat(name.replace('.', '/').concat(ShendiKitInfo.CLASS_SUFFIX));
byte[] classData = null;
try (InputStream input = SKClassLoader.class.getResourceAsStream(name)) {
classData = new byte[input.available()];
input.read(classData, 0, classData.length);
} catch (IOException e) {
Log.printErr("重新加载指定类获取出错: " + name + "---" + e.getMessage());
return null;
}
return sk.defineClass(null, classData, 0, classData.length);
}
return c;
}
具体内容就是先通过 findLoadedClass 先加载,如果为空则通过defineClass来获取
然后我就通过这个方法来加载类
接着测试
...
在普通Java项目中没有问题,在web项目中错误又出现了....
一个权限异常 Access什么的
后来继续查阅,找到了正确的使用方法
自定义类加载器要加载类则需要实现 findClass 方法,代码就如我上面那样
在使用的过程中使用的是 loadClass 方法
接着测试
代码没有问题,也没有错误
但是奇怪的问题又来了
在web项目中依然无法进行热更.
然后根据双亲加载机制,我输出了获取的类和直接xx.class的HashCode
然后发现两个是不一样的,对的 因为是两个类加载器加载的
于是乎做了一堆没用的操作后放弃了
...
然后发现自己对defineClass方法的理解有误,这个方法是直接通过字节定义类,不会被双亲机制什么的所影响,于是我将代码恢复到最初状态
不纠结web项目能不能热更了
收工