2011-04-13 76 views
15

在Java类加载器的正确的做法是:Java类加载器:为什么先搜索父类加载器?

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

所以在系统类路径中定义的类应该总是先加载。 Tomcat定义了每次战争的类加载器,它将系统类加载器作为父类,因此如果尝试加载类,它将首先查看系统类路径,然后查找war文件中定义的类路径。

按我的理解,这是出于两个原因:

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

所以,问题是:

除了上述问题外,还有什么其他的陷阱,以实现一个类加载器不首先做父母的搜索?

+1

JFYI:java.lang.Object不会从WAR加载。在ClassLoader中有一个明确的java.lang检查。它只能从引导位置加载。 – 2011-04-13 15:15:56

回答

3

不是。事实上,它是作为实例化一个URLClassLoader,并给予它null父一样简单:

myClassLoader = new URLClassLoader(myUrlArray, null); 

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

+0

如果你尝试'myClassLoader.loadClass(“[I”)''你会得到'java.lang.ClassNotFoundException',这非常令人惊讶。 – 2015-09-30 23:59:56

3

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

0

如果您根本没有搜索到您的父项,您将失去对所有标准Java对象的访问权限,并且可能根本无法运行。

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

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

13

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

所以基本上可以实施家长优先策略。实施母公司也是可以的。两种策略都有其优缺点。

我给你多一个理由,为什么要实现父 - 先:你减少了在perm内存中加载的类的数量。想象一下,您有多个使用相同库的Web应用程序。随着家长优先库加载一次。随着父母最后它会被加载多次。
但是,以父母为先,所有网络应用都需要使用相同版本的库,而使用父母最后他们可能会使用不同的版本。

+0

有趣的答案。我想知道实现父代最后一个类加载器的最佳策略是什么。要实现父代优先是非常直接的,因为你只需要实现findClass()方法,并且你已经完成设置。为了实现parent-last,看起来你必须重载loadClass(String,boolean),并且可能复制了很多功能(除了类寻找序列)?谢谢 – RAY 2012-07-05 13:01:17

+1

为什么你需要实现你自己的类加载器?你正在试图解决什么样的使用案例?这些是开始谈论实际实施之前的第一个问题。通常实现是由用例驱动的... – Tarlog 2012-07-05 13:34:43

2

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

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