这篇文章是在上一篇文章的基础上进行补充。写这篇文章的原因是因为在今天的面试中,聊到自己小程序后台在线编辑代码,其中涉及到防止非必要重启,我使用自定义类加载去加载某些类,然后面试官问到这样一个问题:如果你第一版的class文件放服务器上去被加载之后,你又修改了源代码重新编辑替换,此时怎么解决?
相关文章:自定义类加载器
听到这个问题的时候,我愣住了,因为我都没明白要解决啥,面试官友情提示了一下该类已经被加载了,我反应过来ClassLoader的loadclass方法中有findLoadedClass()方法,当我们的class文件被加载之后,被覆盖的class文件并不会重新加载,这是因为findLoadedClass调用本地方法findLoadedClass0检查class文件是否加载过。如果加载过,那么直接返回该类,就不会有findClass这个过程,所以说我们重写的自定义类加载器并没有解决替换class文件这个问题(重启的方案我们还是不要说了)。
当时这个问题我没有想到如何解决。
下午回来的时候,我就开始考虑这个问题,当我打开ClassLoader源码的时候,我就想到既然findClass没有被调用,那我loadclass的时候强迫它调用呢?代码如下(重写loadClass):
@Override
public Class loadClass(String name) throws ClassNotFoundException {
if (!"cl.test.TestDyna".equals(name))
return super.loadClass(name);
return findClass(name);
}
main函数去测试一下
ClassLoader classLoader = new MyClassLoader();
Class<?> c1 = classLoader.loadClass("cl.test.TestDyna");
Class<?> c2 = classLoader.loadClass("cl.test.TestDyna");
结果会报错:LinkageError。这是因为每个被加载的Class都需要被链接(link),个人理解就是一个类加载器去加载相同限定名的Class时,就会抛出java.Lang.LinkageError.
执行自定义的类cl.test.TestDyna
执行自定义的类cl.test.TestDyna
Exception in thread "main" java.lang.LinkageError: loader (instance of cl/test/MyClassLoader): attempted duplicate class definition for name: "cl/test/TestDyna"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at cl.test.MyClassLoader.findClass(TestXML.java:73)
at cl.test.MyClassLoader.loadClass(TestXML.java:62)
at cl.test.TestXML.main(TestXML.java:35)
走到这里就很好处理了,既然一个类加载器去加载相同限定名的Class时会出现问题,那么就使用不同的类加载器来处理了。
private static Map<String, Class<?>> map = new HashMap();
private static void loadClass(String name) throws ClassNotFoundException {
ClassLoader classLoader = new MyClassLoader();
Class<?> c = classLoader.loadClass(name);
map.put(name, c);
}
public static void main(String[] args) throws Exception {
loadClass("cl.test.TestDyna");
Class<?> c1 = map.get("cl.test.TestDyna");
loadClass("cl.test.TestDyna");
Class<?> c2 = map.get("cl.test.TestDyna");
System.out.println(c1 == c2);
}
上面可能就是我目前对于此问题回答了。当然可能有更好的答案,这里仅供参考。
1.分布式架构下,有一定并发,如果要生成唯一,位数固定且连续的订单号,订单号某几位每天都要从0开始。你该如何设计,你觉得实现过程中会有哪些问题。
2.分布式事务的解决方案
3.Redis充当分布式锁的时候,如果某一线程获取锁的时效已过期,但是该线程任务还没执行完,可能会发生什么,如何解决。