java 从 .war 文件加载类的顺序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4466526/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Order of class loading from a .war file
提问by SyntaxT3rr0r
I've got a question regarding the guarantees, if any, in the following scenario (note that the question is not "How to do this in a different way?", the question is really about class loading order in the following case (to better understand how class loading works).
我有一个关于保证的问题,如果有的话,在下面的场景中(请注意,问题不是“如何以不同的方式做到这一点?”,问题实际上是关于以下情况下的类加载顺序(到更好地了解类加载的工作原理)。
Here's the hypothetical scenario... There's a .warfile that has the following (partial) directory structure:
这是假设的场景......有一个.war文件具有以下(部分)目录结构:
WEB-INF/classes/com/acme/Bunny.class
.
.
.
WEB-INF/lib/acme.jar
Both Bunny.classfiles have import referencing other classes from acme.jar
两个Bunny.class文件都从acme.jar导入引用其他类
Bunny.classin WEB-INF/classes/...is the only class that has the same name/path that a class from acme.jar.
Bunny.class在WEB-INF /班/ ...是具有相同的名称/路径,从一类唯一的类acme.jar。
The .jarfile acme.jaralso contains com.acme.Bunny(and there are a no special class loader tricks used).
该的.jar文件acme.jar还包含com.acme.Bunny(也有使用没有特殊的类装载器的技巧)。
I understand that the Java spec guarantees that a class won't be loaded until it is actually used (or "manually class-loaded" on purpose) by the program, which is why if you stuff thousands of .jar, say, in a .war, the classloader(s) don't start classloading tens of thousands of classes.
我知道 Java 规范保证在程序实际使用(或故意“手动加载类”)之前不会加载类,这就是为什么如果你在一个.war,类加载器不会开始加载数以万计的类。
(edit)
(编辑)
But what about the order in which the two classes in the examples above are loaded?
但是上面例子中的两个类的加载顺序呢?
should have been phrased:
应该是这样的:
But how is it decided which one of the two classes above is loaded?
但是如何决定加载上述两个类中的哪一个呢?
or something like that :)
或类似的东西 :)
There's one guarantee made: com.acme.Bunnyshall be used before any other class from com.acme....
有一个保证:com.acme.Bunny应在来自com.acme... 的任何其他类之前使用。
Basically, on Wikipedia, the following is written:
基本上,在维基百科上,写了以下内容:
The most complex JAR hell problems arise in circumstances that take advantage of the full complexity of the classloading system. A Java program is not required to use only a single "flat" classloader, but instead may be composed of several (or, in fact, an indefinite number of) nested, cooperating classloaders. Classes loaded by different classloaders may interact in complex ways not fully comprehended by a developer, leading to inexplicable errors or bugs.
最复杂的 JAR 地狱问题出现在充分利用类加载系统复杂性的情况下。Java 程序不需要只使用一个“平面”类加载器,而是可以由多个(或者实际上是无限数量的)嵌套、协作的类加载器组成。由不同的类加载器加载的类可能会以开发人员无法完全理解的复杂方式进行交互,从而导致无法解释的错误或错误。
So I'm wondering: can I be sure that /classes/com/acme/Bunny.classwill be classloaded before the one from .jarinside the WEB-INF/lib/dir or not?
所以我想知道:我可以确定/classes/com/acme/Bunny.class会在WEB-INF/lib/目录中的.jar之前加载类吗?
采纳答案by Cameron Skinner
This questionmay be of some help.
这个问题可能会有一些帮助。
The servlet specification is vague on this. One would expect "WEB-INF/classes" to be searched before "WEB-INF/lib" but it seems that it's up to the servlet container to decide. All you can be sure of is that the container should consistently load one before the other, so you should never see both classes in the same container. The search path maybe configurable, depending on your container.
servlet 规范对此含糊其辞。人们希望在“WEB-INF/lib”之前搜索“WEB-INF/classes”,但似乎由servlet容器决定。您可以确定的是,容器应该始终在另一个之前加载一个,因此您永远不会在同一个容器中看到两个类。搜索路径可能是可配置的,具体取决于您的容器。
Sorry I can't be more specific: welcome to the world of multiple servlet containers. Don't get me started on Websphere fun-and-games.
抱歉,我不能说得更具体了:欢迎来到多个 servlet 容器的世界。不要让我开始使用 Websphere 趣味游戏。
回答by Sajeev
The selected answer is wrong. Servlet spec version 2.4 and 3.0 clearly states that WEB-INF/classes are loaded first and then WEB-INF/lib
选择的答案是错误的。Servlet 规范版本 2.4 和 3.0 明确指出首先加载 WEB-INF/classes,然后加载 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- section SRV.9.5, last paragraph
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- section 10.5, last paragraph
Servlet 3.0:http: //download.oracle.com/otn-pub/jcp/servlet-3.0-fr-oth-JSpec/servlet-3_0-final-spec.pdf- 第 10.5 节,最后一段
The Web application class loader must load classes from the WEB-INF/classes directory first, and then from library JARs in the WEB-INF/lib directory.
Web 应用程序类加载器必须首先从 WEB-INF/classes 目录加载类,然后从 WEB-INF/lib 目录中的库 JAR 加载类。
回答by Berin Loritsch
Both the WEB-INF/lib/*.jar
files and the WEB-INF/classes
directory are in the same ClassLoader. It would be as if you started an application with all the jars listed in the ClassPath. As a class name needs to be resolved, the ClassLoader will find the first class that matches from its resources. The exact order it searches in is nondeterministic--it depends on the platform.
这两个WEB-INF/lib/*.jar
文件和WEB-INF/classes
目录在同一个类加载器。就好像您使用 ClassPath 中列出的所有 jar 启动了一个应用程序。由于需要解析类名,ClassLoader 会从其资源中找到第一个匹配的类。它搜索的确切顺序是不确定的——它取决于平台。
Java Packages were designed to address the problem of name clashes such as what you described. It is never a good idea to deliberately name a class the same as what is bundled in its own jar file. The better solution would be to extend the class and use the new version in your code. If you need to alter functionality of that class, then you might look into the black magic of Java Aspect Oriented Programming.
Java Packages 旨在解决您描述的名称冲突问题。故意将类命名为与其自己的 jar 文件中捆绑的相同的名称绝不是一个好主意。更好的解决方案是扩展类并在代码中使用新版本。如果您需要更改该类的功能,那么您可能会研究 Java Aspect Oriented Programming 的黑魔法。
回答by Kim Burgaard
The answer depends entirely on the concrete class loader hierarchy in use. While the JVM will provide a system class loader, Java EE application servers will typically use custom ClassLoaderimplementations to isolate classes loaded in separate modules and applications, and to enforce security concerns.
答案完全取决于所使用的具体类加载器层次结构。虽然 JVM 将提供系统类加载器,但 Java EE 应用服务器通常会使用自定义ClassLoader实现来隔离加载在单独模块和应用程序中的类,并加强安全问题。
The ClassLoader API does not impose any rules on how concrete implementations resolve class requests. However, the intentof the WEB-INF/lib directory is to allow bundling of app-specific libraries. I suspect most people would expect the jar files in the lib directory to be searched AFTER the root contents of the jar file.
ClassLoader API 没有对具体实现如何解决类请求强加任何规则。然而,意图在WEB-INF / lib目录中是允许的应用程序特定库的捆绑。我怀疑大多数人会期望在 jar 文件的根目录内容之后搜索 lib 目录中的 jar 文件。
I'm not aware that the Java EE specifications establish any such guarantee though, and the interface and documentation for the abstract ClassLoader class certainly doesn't.
我不知道 Java EE 规范建立了任何这样的保证,抽象 ClassLoader 类的接口和文档当然没有。
So, hypothetically, you could have a web container that would end up returning Bunny.class from the jar file insteadof the one from the root hierarchy of the war file.
因此,假设您可以拥有一个最终从 jar 文件而不是从 war 文件的根层次结构返回 Bunny.class 的 Web 容器。
回答by lisak
It depends on the container that deploys the war file. From my experiences, WEB-INF/classes location is always before lib/ on the classpath of a classloader for application context.
这取决于部署war文件的容器。根据我的经验,WEB-INF/classes 位置总是在应用程序上下文的类加载器的类路径上的 lib/ 之前。
Classes are loaded right after the deployer expands the war into the container. Usually when a context loader listener servlet is loaded and the rest of the application with it. It can be done in many ways such as by a reference to default servlet or loading spring context etc.
在部署者将War扩展到容器中后,类会立即加载。通常当上下文加载器侦听器 servlet 被加载时,应用程序的其余部分也随之加载。它可以通过多种方式完成,例如通过引用默认 servlet 或加载 spring 上下文等。
So that WEB-INF/classes/com/acme/Bunny.class should be loaded first afaik.
所以应该首先加载 WEB-INF/classes/com/acme/Bunny.class afaik。
回答by Laurence Gonsalves
You seem to be conflating two different senses of "before".
您似乎将“之前”的两种不同含义混为一谈。
Classes are loaded in the order they are used. This is temporal, and is the more correct use of "before". If Foo is used before Bar then it'll be loaded before Bar.
类按照它们的使用顺序加载。这是暂时的,是“before”的更正确用法。如果 Foo 在 Bar 之前使用,那么它将在 Bar 之前加载。
You're also talking about whether classes/com/acme/Bunny.class will be loaded "before" acme.jar's com/acme/Bunny.class. The second one won't be loaded at all. The classloader will look for the first instance of com/acme/Bunny.class on the classpath, find the one in classes, and stop looking.
您还讨论了 classes/com/acme/Bunny.class 是否会在 acme.jar 的 com/acme/Bunny.class 之前“加载”。第二个根本不会被加载。类加载器将在类路径上查找 com/acme/Bunny.class 的第一个实例,在类中找到该实例,然后停止查找。