• java自定义classloader引发的思考


    引用

    classloader机制

    • 如下图所示,java的classloader是双亲委派机制。会首先从父classloader加载指定的class,如果加载不到才会从子classloader中加载。
    • 主要这里的图片主要用于体现classloader的父子关系,实际上实现时并不一定存在继承关系。比如AppClassLoader的父classLoader是ExtClassLoader,但是实际实现时两者都是继承自URLClassLoader的。

    自定义classloader

    Animal类&包结构

    • 包结构如图:

    测试入口

    • 输出结果如图所示:

    思考1

    • 我们定义的classloader真的被运行了吗?
    • 实际上如果打一些日志或者是debug进去看下,会发现我们重写的方法并没有被执行,这是java classloader的委派机制搞的鬼,我们可以发现定制的TinglangClassLoader的父classloader为URLClassLoader,在URLClassLoader中就已经找到了Animal类了。
    • 所以这里可以重写loadClass方法来保证我们的classLoader被执行。

    思考2

    • 我们将代码做一些变种,如下图所示:
    • 执行结果直接抛异常了
    • 这是由于Animal类来源于两个不同的类加载器。如果只是需要执行Animal中的say方法的话,直接反射调用即可,如下图所示:

    思考3

    • 我们再将代码做一下变化,如下图所示,Animal作为一个普通内部类来实现,如下图所示:
    • 可以看到代码已经提示无法实例化内部类了,这个是由于要实例化非静态的内部类对象,必须要先实例化外部类的对象,可以采用下面的方法来解决:
    • ps:这里内部类有public修饰符~

    思考4

    • tomcat也是定义了自己的classloader,那么为啥不用jvm提供的classloader呢?
    • 结合相关的资料主要是三个方面的目的:
      • webapp隔离:由于各个webapp中的class和lib文件需要相互隔离,不能出现一个应用中加载的类库会影响到另一个应用的情况。
      • 安全性:与jvm相同,tomcat也期望使用单独的classloader去装载tomcat自身的类库,以免其他恶意或者无意的破坏。
      • 热部署:tomcat修改文件可以不用重启自动装载类库,这个点后面我们会单独抽取示例。

    思考5

    • 既然ExtClassLoader是读取特定目录下的class文件,那么如果我将自定义的class文件移到$JAVA_HOME/jre/lib/ext/目录下是不是就能够达到指定classloader加载类的目标呢?
    • 这个点是可以的,但是必须要求是jar。

    思考6

    • 类加载器常见的用途有类的隔离和热替换,类的隔离非常好理解,那么热替换呢?
    • 仍然以我们之前的代码为例,如下图所示:
    • 在程序运行过程中更新并编译Animal类中say方法
    • 可以看到运行结果如图所示:
    • ps:注意第一张图中的红色框框部分,如果修改为Thread.currentThread().getContextClassLoader()会发现实际上不会起作用,这是由于要想实现同一个类的不同版本的共存,这些不同的版本必须由不同的类加载器进行加载,因此就不能把这些类的加载工作委托给类加载器来完成,因为它们只有一份。
  • 相关阅读:
    Sql之表的连接总结
    sql之独立子查询和相关子查询总结
    canvas 绘点图
    gulp插件
    jquery插件开发模板
    js中substring和substr的用法比较
    phpStudy 2016 更新下载,新版支持php7.0
    phpStudy for Linux (lnmp+lamp一键安装包)
    用 Function.apply() 的参数数组化来提高 JavaScript程序性能
    Js apply() call()使用详解
  • 原文地址:https://www.cnblogs.com/editice/p/5420712.html
Copyright © 2020-2023  润新知