Java类加载器:为什么首先搜索父类加载器?

Java中类加载器的正确行为是:

  1. 如果已加载,则返回该类
  2. 调用父loadClass()
  3. 尝试加载类本身。

因此,系统类路径中定义的类应始终首先加载。 Tomcat定义了每个war的类加载器,它将系统类加载器作为父类,因此如果您尝试加载类,它将首先查看系统类路径,然后查看war文件中定义的类路径。

据我了解,这有两个原因:

  1. 避免使用不同版本的类的问题。 想象一下,我在战争中重新定义了java.lang.Object,这将是一场噩梦。
  2. 为了避免对子类加载器的依赖:系统类加载器不能依赖子类加载器:例如,重新部署战争是很困难的。

所以,问题是:

除了上述问题之外,实现不首先进行父搜索的类加载器还有其他缺陷吗?

Tomcat首先不查找父类加载器。 实际上它恰恰相反:它首先查看webapp,然后转到父类加载器(Tomcat 6/7的“lib”和Tomcat 5.5的“共享”)。 这个规则的例外是系统类(我认为所有包含java。*和javax。*的东西),这些类只在系统类加载器中查找。 我相信他们这样做的原因是你说的第一个原因。

所以基本上可以实现父优先策略。 实现parent-last也没问题。 这两种策略都有其缺点和优点。

我将再给你一个理由,为什么要实现parent-first:你减少了perm内存中加载的类的数量。 想象一下,您有多个使用相同库的Web应用程序。 使用parent-first将库加载一次。 使用parent-last,它将被多次加载。
但是,对于父级优先,所有Web应用程序都需要使用相同版本的库,而使用parent-last时,它们可能使用不同的版本。

并不是的。 事实上,它就像实例化URLClassLoader并为父级赋予null一样简单:

 myClassLoader = new URLClassLoader(myUrlArray, null); 

http://download.oracle.com/javase/6/docs/api/java/net/URLClassLoader.html

我能想到的另一个原因是确保类路径按预期工作。 通过首先搜索父级,您实际上将父级的类路径(即系统类路径)放在子级的类路径之前。 因此,如果您在使用-cp启动jvm时指定特定的jar,它们会“隐藏”您尝试加载的任何存档中包含的任何jar。 如果您不先检查父级,则子级的类路径将遮蔽父级。

Tarlog是正确的,你不必这样做。 Java没有设想像tomcat这样的用例。

但是,为什么容器在一个VM中托管多个应用程序是值得怀疑的。 单独的流程更好。

如果您根本不搜索父级,则将无法访问所有标准Java对象,并且可能根本无法运行。

但在尝试父级之前,首先搜索自己的类加载器是合理的。 如果要覆盖上面提供的类的行为,则需要以这种方式执行。

JVM没有,因为首先搜索你的父母是最有意义的。 但是,如果你知道自己在做什么,你可以用类加载器做一些非常有趣的事情。 看看Classworlds 。