Java类加载器:为什么首先搜索父类加载器?
Java中类加载器的正确行为是:
- 如果已加载,则返回该类
- 调用父loadClass()
- 尝试加载类本身。
因此,系统类路径中定义的类应始终首先加载。 Tomcat定义了每个war的类加载器,它将系统类加载器作为父类,因此如果您尝试加载类,它将首先查看系统类路径,然后查看war文件中定义的类路径。
据我了解,这有两个原因:
- 避免使用不同版本的类的问题。 想象一下,我在战争中重新定义了java.lang.Object,这将是一场噩梦。
- 为了避免对子类加载器的依赖:系统类加载器不能依赖子类加载器:例如,重新部署战争是很困难的。
所以,问题是:
除了上述问题之外,实现不首先进行父搜索的类加载器还有其他缺陷吗?
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 。
- JVM如何开始寻找类?
- 如果不使用返回值,Class.forName()的用途是什么?
- ClassLoader.getResources在Weblogic / Spring应用程序上返回一个空的Enumeration
- WAS 8.5:java.lang.ClassCastException:org.apache.xerces.jaxp.SAXParserFactoryImpl与javax.xml.parsers.SAXParserFactory不兼容
- Java classLoader困境与锁定的jar子
- 使用自定义类加载器配置org.apache.log4j.ConsoleAppender
- Java中的“new”做什么做了类加载器?
- 除了混淆之外,还可以做些什么来保护jar文件?
- 线程创建监听器