java自定义classloader引发的思考
2024-08-31 11:02:41
引用
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()
会发现实际上不会起作用,这是由于要想实现同一个类的不同版本的共存,这些不同的版本必须由不同的类加载器进行加载,因此就不能把这些类的加载工作委托给类加载器来完成,因为它们只有一份。
最新文章
- springmvc上传文件,抄别人的
- C++序列化、反序列化
- 如何消除inline-block元素间间距问题(转)
- servlet/jsp详解
- SQL Server 数据库的安全管理(登录、角色、权限)
- 浅谈Oracle表之间各种连接
- BZOJ1114 : [POI2008]鲁滨逊逃生Rob
- Intellij IDEA @Override 标红
- ActionScript基本语法讲解
- Android java.lang.ClassCastException
- C#的tooltip自动消失之后就不再显示了解决办法
- js设置文本框只能输入数字
- android开发艺术探索读书笔记之-------view的事件分发机制
- Java编程之委托代理回调、内部类以及匿名内部类回调(闭包回调)
- 深入分析Java的String类的方法与特点
- PHP和Go中的闭包变量作用域
- VUE-011-通过 v-if 和 v-for 实现特定值的列表循环匹配,并显示满足匹配条件的值
- POJ 2378.Tree Cutting 树形dp 树的重心
- 错误记录:vue跟vue编译器版本不一致
- json 的类型