小介绍
如您所知,默认情况下,Java使用引导类加载器和系统类加载器。第一个负责加载引导程序类(其类路径包含rt.jar之类的工件),第二个负责保存应用程序的类路径。通常,在您的环境变量中定义或在JVM中给定的类路径开始使用该
-cp参数。
答案
仅当发生以下两种情况之一时,
com.example.SomeClass您的自定义类加载器
Custom才会加载该类:在启动时定义自定义类加载器以用作系统类加载器,或者在运行时通过该类显式加载类。
关于每个选项的更多信息:
- 在应用程序启动时 :您可以定义在启动JVM实例时要使用自己的Java而不是使用Java的默认系统类加载器。为此,只需定义以下环境变量来调用java:
-Djava.system.class.loader=my.tests.classloaders.Custom
在这种情况下,发生的情况是该类JVM实例中应用程序中的 所有 类实际上将由
Custom类加载器加载。
- 在运行时 :您可以在运行时使用自定义类加载器加载类。这是通过创建自定义类加载器的实例并从中加载类来实现的
ClassLoader classloader = new CustomClassLoader(); Class someClass = classloader.loadClass("com.example.SomeClass");
就像@Noofiz在他的回答中所说,一旦您加载了一个类,就需要通过关联的类加载器来加载所有需要且尚未加载的引用类。因此,如果使用自定义类加载器加载一个类,则所有引用的类也将通过该类加载。加载所有类时,您可以执行任何操作,记录正在加载的类,委托给父类加载器,自己加载这些类…
一些额外的信息
通常,实现自定义类加载器的最佳方法是使用您提到的委托模型。这是因为实际上,一个类不仅由类的字节码定义,而且还由其类加载器定义,这意味着
由两个不同的类加载器加载的类将不是同一类 。
这意味着当您的自定义类加载器委托给它的父类时,您要确保该类可以在 更大范围内使用 。在大多数情况下,这将是您想要的,但并非总是如此。
如果出于某种原因要隔离类,则可以以其他方式实现自定义类加载器。首先,它尝试自行加载该类,并且仅在找不到该类(或者是JVM系统类或您可能要跳过的任何其他类)的情况下,才将其委托给其父类。例如,Web应用程序容器以这种方式工作,从而允许重新部署上下文(基本上它们会丢弃类加载器,并创建一个新的类加载器来再次加载所有内容),并在Web应用程序之间实现完全的类隔离。
正如我已经说过的,处理类加载绝不是一件容易的事,或者您真的知道自己在做什么,或者您肯定会遇到一些奇怪的伏都教麻烦。
也许已经太离题了,但是如果您想更多 地 了解类加载器和隔离的知识,可以查看一个名为classworlds的旧开源项目。即使这个项目很旧,我还是建议您这样做,因为它是一个很小的项目,里面充满了有关类加载机制的知识,您可以轻松地了解这些知识。



