首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自定义类加载器加载过Class文件被替换后如何生效

自定义类加载器加载过Class文件被替换后如何生效

作者头像
每天学Java
发布2020-06-02 10:13:22
1.7K0
发布2020-06-02 10:13:22
举报
文章被收录于专栏:每天学Java每天学Java

说明

这篇文章是在上一篇文章的基础上进行补充。写这篇文章的原因是因为在今天的面试中,聊到自己小程序后台在线编辑代码,其中涉及到防止非必要重启,我使用自定义类加载去加载某些类,然后面试官问到这样一个问题:如果你第一版的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充当分布式锁的时候,如果某一线程获取锁的时效已过期,但是该线程任务还没执行完,可能会发生什么,如何解决。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 每天学Java 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 说明
  • 正文
  • 解决方案
  • 其他问题
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档