【问题标题】:Java classloaders: why search the parent classloader first?Java 类加载器:为什么要先搜索父类加载器?
【发布时间】:2011-04-13 13:46:15
【问题描述】:

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

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

所以系统类路径中定义的类应该总是首先被加载。 Tomcat为每个war定义了类加载器,它以系统类加载器为父类,所以如果你尝试加载一个类,它会先在系统类路径中查找,然后在war文件中定义的类路径中查找。

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

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

所以,问题是:

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

【问题讨论】:

  • JFYI:不会从 WAR 加载 java.lang.Object。在 ClassLoader 中有对 java.lang 的显式检查。它只能从引导位置加载。

标签: java classloader


【解决方案1】:

Tomcat 不会首先寻找父类加载器。实际上它的作用正好相反:它首先在 webapp 中查找,然后才进入父类加载器(对于 Tomcat 6/7 是“lib”,对于 Tomcat 5.5 是“shared”)。这条规则的例外是系统类(我认为所有有包 java.* 和 javax.* 的东西),这些类只在系统类加载器中查看。我相信他们这样做的原因是您所说的#1 原因。

所以基本上可以实施父母优先的策略。实现 parent-last 也可以。这两种策略各有利弊。

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

【讨论】:

  • 有趣的答案。我想知道实现 parent-last 类加载器的最佳策略是什么。实现父优先是非常简单的,因为您只需要实现 findClass() 方法,就可以了。要实现 parent-last,您似乎必须重写 loadClass(String, boolean),并且可能在那里复制很多功能(类查找序列除外)?谢谢
  • 为什么需要实现自己的类加载器?您要解决什么用例?这些是开始谈论实际实施之前的第一个问题。通常实现是由用例驱动的......
【解决方案2】:

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

myClassLoader = new URLClassLoader(myUrlArray, null);

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

【讨论】:

  • 如果您尝试myClassLoader.loadClass("[I"),您将获得java.lang.ClassNotFoundException,这非常令人惊讶。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

    • 1.具有小用户群的大型应用程序可以分成单独的部分并独立提交。 2. 大型组织可以为部门职能分配一台服务器,并且与该职能相关的所有应用程序都可以驻留在一个地方,从而节省了 $$$$ 的硬件成本。
    【解决方案5】:

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

    但是在尝试父类之前先搜索自己的类加载器是合理的。如果你想覆盖你上面的一个类提供的行为,你需要这样做。

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

    【讨论】:

      【解决方案6】:

      Tomcat Web 应用程序类加载器不遵守“先使用父级”。如docs中所述:

      如上所述,Web 应用程序类加载器不同于默认的 Java 委托模型(根据 Servlet 规范,版本 2.4,第 9.7.2 节 Web 应用程序类加载器中的建议)。当处理从 Web 应用程序的 WebappX 类加载器加载类的请求时,该类加载器将首先在本地存储库中查找,而不是在查找之前进行委托。也有例外。属于 JRE 基类的类不能被覆盖。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-07-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多