什么是Java ClassLoader?

问题描述 投票:167回答:7

在几个简单的句子中,什么是Java ClassLoader,何时使用以及为什么?

好的,我读了一篇wiki文章。 ClassLoader加载类。好。因此,如果我包含jar文件并导入,则ClassLoader可以完成这项工作。

我为什么要打扰这个ClassLoader?我从未使用它,也不知道它存在。

问题是,为什么ClassLoader类存在?而且,你如何在实践中使用它? (案件存在,我知道。)

java classloader
7个回答
217
投票

来自Sun的这个漂亮的tutorial

动机

使用静态编译的编程语言(如C和C ++)编写的应用程序将编译为本机特定于机器的指令并保存为可执行文件。将代码组合成可执行本机代码的过程称为链接 - 将单独编译的代码与共享库代码合并以创建可执行应用程序。这在动态编译的编程语言(例如Java)中是不同的。在Java中,Java编译器生成的.class文件保持原样,直到加载到Java虚拟机(JVM)中 - 换句话说,链接过程由JVM在运行时执行。类根据“需要”加载到JVM中。当一个加载的类依赖于另一个类时,那么该类也被加载。

启动Java应用程序时,要运行的第一个类(或应用程序的入口点)是具有名为main()的public static void方法的类。此类通常具有对其他类的引用,并且所有加载引用类的尝试都由类加载器执行。

要了解这种递归类加载以及一般的类加载想法,请考虑以下简单类:

public class HelloApp {
   public static void main(String argv[]) {
      System.out.println("Aloha! Hello and Bye");
   }
}

如果您运行此类指定-verbose:class命令行选项,以便它打印正在加载的类,您将获得如下所示的输出。请注意,这只是一个部分输出,因为列表太长而无法在此处显示。

prmpt>java -verbose:class HelloApp



[Opened C:\Program Files\Java\jre1.5.0\lib\rt.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jsse.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jce.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\charsets.jar]
[Loaded java.lang.Object from shared objects file]
[Loaded java.io.Serializable from shared objects file]
[Loaded java.lang.Comparable from shared objects file]
[Loaded java.lang.CharSequence from shared objects file]
[Loaded java.lang.String from shared objects file]
[Loaded java.lang.reflect.GenericDeclaration from shared objects file]
[Loaded java.lang.reflect.Type from shared objects file]
[Loaded java.lang.reflect.AnnotatedElement from shared objects file]
[Loaded java.lang.Class from shared objects file]
[Loaded java.lang.Cloneable from shared objects file]
[Loaded java.lang.ClassLoader from shared objects file]
[Loaded java.lang.System from shared objects file]
[Loaded java.lang.Throwable from shared objects file]
.
.
.
[Loaded java.security.BasicPermissionCollection from shared objects file]
[Loaded java.security.Principal from shared objects file]
[Loaded java.security.cert.Certificate from shared objects file]
[Loaded HelloApp from file:/C:/classes/]
Aloha! Hello and Bye
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]

如您所见,首先加载应用程序类(HelloApp)所需的Java运行时类。

Java 2平台中的类加载器

Java编程语言不断发展,使应用程序开发人员的日常生活变得更加轻松。这是通过提供简化生活的API来实现的,它允许您专注于业务逻辑而不是基本机制的实现细节。最近,J2SE 1.5更改为J2SE 5.0,以反映Java平台的成熟度。

从JDK 1.2开始,内置于JVM中的引导类加载器负责加载Java运行时的类。此类加载器仅加载在引导类路径中找到的类,并且由于这些是受信任的类,因此不会对不受信任的类执行验证过程。除了引导类加载器之外,JVM还有一个扩展类加载器,负责从标准扩展API加载类,以及一个系统类加载器,它从一般类路径和应用程序类加载类。

由于存在多个类加载器,因此它们在树中表示,其根是引导类加载器。每个类加载器都有对其父类加载器的引用。当要求类加载器加载类时,它会在尝试加载项本身之前查询其父类加载器。父母反过来咨询其父母,依此类推。所以只有在所有祖先类加载器都找不到当前类加载器涉及的类之后。换句话说,使用委托模型。

java.lang.ClassLoader类

java.lang.ClassLoader是一个抽象类,可以由需要扩展JVM动态加载类的方式的应用程序进行子类化。 java.lang.ClassLoader(及其子类)中的构造函数允许您在实例化新的类加载器时指定父级。如果未明确指定父级,则将将虚拟机的系统类装入器指定为默认父级。换句话说,ClassLoader类使用委托模型来搜索类和资源。因此,ClassLoader的每个实例都有一个关联的父类加载器,因此在请求查找一个或多个类时,在尝试查找类或资源本身之前,该任务被委托给其父类加载器。 ClassLoader的loadClass()方法在调用加载类时按顺序执行以下任务:

如果已经加载了一个类,则返回它。否则,它将搜索新类委托给父类加载器。如果父类加载器没有找到该类,则loadClass()调用方法findClass()来查找并加载该类。如果父类加载器找不到类,则finalClass()方法在当前类加载器中搜索类。


原始文章中还有更多内容,它还向您展示了如何实现自己的网络类加载器,它可以回答您关于原因(以及如何)的问题。另见API docs


44
投票

大多数Java开发人员永远不需要显式使用类加载器(除了加载资源以便它们在JAR中捆绑时仍然有效),更不用说编写自己的了。

ClassLoaders在大型系统和服务器应用程序中用于执行以下操作:

  • 模块化系统并在运行时加载,卸载和更新模块
  • 并行使用不同版本的API库(例如XML解析器)
  • 隔离在同一JVM中运行的不同应用程序(确保它们不会相互干扰,例如通过静态变量)

27
投票

问题是“为什么要打扰这个ClassLoader类”?

好吧,大多数情况下,如果他们出错,你可以解决问题:-)。

这是真的,只要您编写一个应用程序,将其编译为JAR并且可能包含一些额外的库JAR,您就不需要了解类加载器,它只会起作用。

尽管如此,了解类加载器和类加载有助于更好地理解幕后发生的事情。例如,“静态初始化器”将在加载类时运行,因此要了解它们何时运行,您需要知道类加载器如何决定何时加载它们。

还有..你怎么在实践中使用它?

对于简单的情况,您不需要它们。但是,如果您需要在运行时动态加载代码并使用显式控制来源(例如,通过网络加载,加载编译时不可用的插件等),您可能需要执行更多操作。然后你可以,例如编写自己的类加载器。请参阅其他答案的链接。


12
投票

Java中的ClassLoader是一个用于在Java中加载类文件的类。 Java代码由javac编译器编译成类文件,JVM通过执行类文件中编写的字节代码执行Java程序。

ClassLoader负责从文件系统,网络或任何其他来源加载类文件。 Java,Bootstrap,Extension和System或Application类加载器中使用了三个默认的类加载器。

ClassLoader


How ClassLoader works

## ClassLoader与JVM enter image description here的交互

更多@:how-classloader-works-in-java.html


4
投票

类加载器是JVM的一个功能组件,它将类数据从“.class”文件或从网络加载到堆中的方法区域。

看起来像JVM的一个组成部分,但作为最终的java用户,我为什么要关注它?原因如下:

每个类加载器都有自己的名称空间,特定类加载器调用的类进入它的名称空间。

由两个不同的类加载器调用的类将不具有彼此的可见性,从而增强了安全性。

类加载器父子代理机制确保java api类永远不会被未经授权的代码攻击。

有关详细信息,请查看here


1
投票

类加载器是分层的。类被引入JVM,因为它们在已经在JVM中运行的类中由名称引用。

如何加载第一类? 第一个类是在你的类中声明的static main()方法的帮助下加载的。所有后续加载的类都由已加载并运行的类加载。

类加载器创建命名空间。所有JVM都包含至少一个嵌入在JVM中的类加载器,称为原始(或引导)类加载器。这是一回事,我们将看看非原始类加载器。 JVM中有钩子,允许用户定义的类加载器代替原始类加载器。以下是JVM创建的类加载器。

Bootstrap(原始)此类加载器无法重新加载。加载JDK内部类,java。*包(通常加载rt.jar和i18n.jar)。 Extesions此类加载器无法重新加载。从JDK扩展目录(通常是JRE的lib / ext)加载jar文件。系统此类加载器无法重新加载。从系统类路径加载类。

http://www.sbalasani.com/2015/01/java-class-loaders.html


1
投票

当你问为什么ClassLoader类存在时,原因很简单 - 它是负责在运行时查找和加载类文件的类。

让我们详细说明一下。

在JVM中,每个类都由java.lang.ClassLoader的某个实例加载。每当你通常的Java程序启动java <classname>命令启动一个新的JVM时,第一步是加载所有正确工作所需的内存中的密钥类,如java.lang.Object和其他运行时类(rt.jar)。

现在,ClassLoader实际上有3个部分:

  • BootstrapClassLoader负责使这些类可用,即将这些类加载到内存中。
  • 下一个任务是将任何外部库/ JAR加载到内存中,以便正常运行应用程序。 ExtClassLoader负责这项任务。这个类加载器负责加载java.ext.dirs路径中提到的所有.jar文件。
  • 第三个和主要的重要类加载器是AppClassLoader。应用程序类加载器负责加载java.class.path系统属性中提到的类文件。

同样重要的是要注意,可以覆盖默认的ClassLoader实现,使您能够以有用和有趣的方式自定义JVM,从而允许您完全重新定义类文件如何进入系统。

enter image description here

请查看以了解有关Java Class Loader的更多信息。

© www.soinside.com 2019 - 2024. All rights reserved.