我在以下场景中有关于担保的问题(如果有的话)(注意问题不是“如何以不同的方式做到这一点?”,问题是真的关于以下情况下的类加载顺序(为了更好地理解类加载的工作原理)。
这是假设情景......有一个 .war 文件,它具有以下(部分)目录结构:
WEB-INF/classes/com/acme/Bunny.class
.
.
.
WEB-INF/lib/acme.jar
两个 Bunny.class 文件都有导入引用来自 acme.jar 的其他类
WEB-INF / classes /...中的Bunny.class 是唯一一个与 acme中的类具有相同名称/路径的类。罐
.jar 文件 acme.jar 还包含 com.acme.Bunny (并且没有使用特殊的类加载器技巧)
据我所知,Java规范保证在程序实际使用(或故意“手动加载类似”)之前不会加载类,这就是为什么如果你填充数千个.jar,在.war中,类加载器不会开始加载数万个类。
(编辑)
但是顺序呢? 上面例子中的两个类是 装?
本来应该措辞:
但它是如何决定哪一个 上面有两个类?
或类似的东西:)
有一个保证: com.acme.Bunny 应该在 com.acme ... 的任何其他类之前使用。
基本上,在维基百科上,写了以下内容:
最复杂的JAR地狱问题 在需要的情况下出现 完全复杂的优点 类加载系统。一个Java 程序不需要只使用一个 单个“平面”类加载器,但相反 可能由几个(或,在 事实上,无限数量的嵌套, 合作的类加载器。类 由不同的类加载器加载可能 不完全以复杂的方式进行交互 由开发人员理解,领导 无法解释的错误或错误。
所以我想知道:我可以确定 /classes/com/acme/Bunny.class 将在 .jar 中的
答案 0 :(得分:13)
所选答案错误。 Servlet规范版本2.4和3.0明确指出首先加载WEB-INF /类,然后加载WEB-INF / lib
Servlet 2.4:http://download.oracle.com/otn-pub/jcp/servlet-2.4-fr-spec-oth-JSpec/servlet-2_4-fr-spec.pdf - 第SRV.9.5节,最后一段
Servlet 3.0:http://download.oracle.com/otn-pub/jcp/servlet-3.0-fr-oth-JSpec/servlet-3_0-final-spec.pdf - 第10.5节,最后一段
Web应用程序类加载器必须从WEB-INF / classes加载类 首先是目录,然后是WEB-INF / lib目录中的库JAR。
答案 1 :(得分:8)
This question可能会有所帮助。
servlet规范对此很模糊。人们期望在“WEB-INF / lib”之前搜索“WEB-INF / classes”,但似乎由servlet容器来决定。您可以确定的是,容器应该始终先加载一个容器,因此您永远不应该在同一个容器中看到这两个类。搜索路径可以可配置,具体取决于您的容器。
抱歉,我不能更具体:欢迎来到多个servlet容器的世界。不要让我开始使用Websphere的趣味游戏。
答案 2 :(得分:2)
WEB-INF/lib/*.jar
个文件和WEB-INF/classes
目录都在同一个ClassLoader中。就好像您使用ClassPath中列出的所有jar启动了一个应用程序。由于需要解析类名,ClassLoader将找到与其资源匹配的第一个类。它搜索的确切顺序是不确定的 - 它取决于平台。
Java包旨在解决名称冲突问题,例如您所描述的内容。故意将类命名为与其自己的jar文件中捆绑的类相同,这绝不是一个好主意。更好的解决方案是扩展类并在代码中使用新版本。如果您需要更改该类的功能,那么您可能会研究Java面向方面编程的黑魔法。
答案 3 :(得分:1)
答案完全取决于使用的具体类加载器层次结构。虽然JVM将提供系统类加载器,但Java EE应用程序服务器通常使用自定义ClassLoader实现来隔离在单独的模块和应用程序中加载的类,并强制执行安全性问题。
ClassLoader API不对具体实现如何解析类请求施加任何规则。但是,WEB-INF / lib目录的 intent 允许bundling of app-specific libraries。我怀疑大多数人都希望在jar文件的根目录之后搜索lib目录中的jar文件。
我不知道Java EE规范虽然建立了这样的保证,但抽象的ClassLoader类的接口和文档肯定没有。
因此,假设您可以拥有一个Web容器,最终将从war文件的根层次结构中的jar文件而不是返回Bunny.class。
答案 4 :(得分:1)
这取决于部署war文件的容器。根据我的经验,WEB-INF / classes位置始终位于lib / on应用程序上下文的类加载器的类路径之前。
在部署者将战争扩展到容器后立即加载类。通常在加载上下文加载器侦听器servlet时,使用它加载应用程序的其余部分。它可以通过多种方式完成,例如通过引用默认servlet或加载spring上下文等。
因此应首先加载WEB-INF / classes / com / acme / Bunny.class。
答案 5 :(得分:0)
你似乎在混淆“之前”的两种不同感官。
按照使用顺序加载类。这是暂时的,是对“之前”更正确的使用。如果在Bar之前使用Foo,那么它将在Bar之前加载。
你还在谈论是否将在“acme.jar”的com / acme / Bunny.class之前加载classes / com / acme / Bunny.class。第二个根本不会加载。类加载器将在类路径中查找com / acme / Bunny.class的第一个实例,在类中找到一个,然后停止查找。