jvm类加载机制和类加载器_在JVM之下–类加载器

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 17:22   2587   0

jvm类加载机制和类加载器

在许多开发人员中,类加载器是Java语言的底层,并且经常被忽略。 在ZeroTurnaround上 ,我们的开发人员必须生活,呼吸,饮食,喝酒,并且几乎与类加载器保持亲密关系,以生产JRebel技术,该技术在类加载器级别进行交互以提供实时运行时类重新加载,从而避免了冗长的重建/重新包装/重新部署周期。
这是我们从类加载器中学到的一些知识,其中包括一些调试技巧,这些技巧将有望为您节省时间和将来的总办事处。

一个类加载器只是一个普通的java对象

是的,这并不聪明,除了JVM中的系统类加载器之外,类加载器只是一个Java对象! 这是一个抽象类ClassLoader,可以由您创建的类实现。 这是API:

public abstract class ClassLoader {

 public Class loadClass(String name);

 protected Class defineClass(byte[] b);

 public URL getResource(String name);

 public Enumeration getResources(String name);

 public ClassLoader getParent()

}

看起来很简单,对吧? 让我们逐个方法看一下。 中心方法是loadClass,它仅使用String类名,然后返回实际的Class对象。 如果您以前使用过类加载器,则这是最熟悉的方法,因为它是日常编码中使用最多的方法。 defineClass是JVM中的最终方法,该方法从文件或网络上的某个位置获取字节数组,并产生相同的结果(即Class对象)。

类加载器还可以从类路径中找到资源。 它的工作方式与loadClass方法类似。 有几种方法,getResource和getResources,它们返回一个URL或URL的枚举,这些URL或URL的枚举指向资源,该资源表示作为输入传递给该方法的名称。

每个类加载器都有一个父级。 getParent返回与Java继承无关的classloader父类,而是一个链表样式的连接。 稍后我们将对此进行更深入的研究。

类加载器是惰性的,因此仅在运行时请求类时才加载类。 类是由调用该类的资源加载的,因此,在运行时,一个类可以由多个类加载器加载,具体取决于从何处引用它们,以及哪个类加载器加载了引用的类。 让我们看一些代码。

public class A {

 public void doSmth() {

    B b = new B();

    b.doSmthElse();

 }

}

在这里,我们有类A在其方法范围内调用类B的构造函数。 在幕后这是正在发生的事情

A.class.getClassLoader().loadClass(“B”);

最初加载类A的类加载器被调用以加载类B。

类加载器是分层的,但是像孩子一样,他们并不总是问父母

每个类加载器都有一个父类加载器。 当一个类加载器被要求提供一个类时,它通常会直接转到父类加载器,首先调用loadClass,而后者又可能会询问它的父类,依此类推。 如果要求两个具有相同父级的类加载器加载同一类,则父级将只执行一次。 当两个类加载器分别加载同一个类时,这将变得很麻烦,因为这可能会导致问题,我们将在后面讨论。

当设计JEE规范时,Web类加载器被设计为以相反的方式工作-很棒。 让我们看一下下图作为示例。


模块WAR1具有自己的类加载器,并且更愿意自行加载类,而不是委托给其父级(由App1.ear定义的类加载器)。 这意味着不同的WAR模块(例如WAR1和WAR2)无法看到彼此的类。 App1.ear模块具有自己的类加载器,并且是WAR1和WAR2类加载器的父级。 当WAR1和WAR2类加载器需要在层次结构中委派请求时,即WAR类加载器范围之外需要一个类时,它们将使用App1.ear类加载器。 实际上,WAR类会覆盖同时存在的EAR类。 最后,EAR类加载器的父级是容器类加载器。 EAR类加载器会将请求委派给容器类加载器,但是它的执行方式与WAR类加载器不同,因为EAR类加载器实际上更喜欢委托而不是本地类。 如您所见,这变得非常繁琐,并且与普通的JSE类加载行为不同。

平面类路径

我们讨论了系统类加载器如何通过类路径查找已请求vV.{X

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP