Java 类加载器:为什么要先搜索父类加载器?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5650334/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 12:05:28  来源:igfitidea点击:

Java classloaders: why search the parent classloader first?

javaclassloader

提问by Matthew Farwell

The correct behaviour for a classloader in Java is to:

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

  1. If it has already been loaded, return the class
  2. Call the parent loadClass()
  3. Try and load the class itself.
  1. 如果已经加载,返回类
  2. 调用父级 loadClass()
  3. 尝试加载类本身。

So the class defined in the system classpath should always get loaded first. Tomcat defines classloader per war, which has the system classloader as a parent, so if you try to load a class, it will first look in the system classpath and then in the classpath defined in the war file.

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

As per my understanding, this is for two reasons:

根据我的理解,这有两个原因:

  1. To avoid problems with different versions of classes being used. Imagine I redefined java.lang.Object in a war, it would be a nightmare.
  2. To avoid dependencies on child classloaders: The system classloader cannot depend on child classloaders: it would be hard to redeploy a war, for instance.
  1. 避免使用不同版本的类时出现问题。想象一下,我在一场War中重新定义了 java.lang.Object,那将是一场噩梦。
  2. 为了避免对子类加载器的依赖:系统类加载器不能依赖于子类加载器:例如,很难重新部署War。

So, the question is:

所以,问题是:

In addition to the above problems, are there any other pitfalls to implementing a classloader which does not do a parent search first?

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

回答by Tarlog

Tomcat doesn't looks for a parent classloader first. Actually it does the opposite: it first looks in the webapp and only then goes to the parent classloader (which is "lib" for Tomcat 6/7 and "shared" for Tomcat 5.5). The exception for this rule are the system classes (I think everything that has package java.* and javax.*), these classes were looked only in the system classloader. I believe the reason they do it is the #1 reason you stated.

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

So basically it's ok to implement parent-first strategy. It's also ok to implement parent-last. Both strategies have their cons and pros.

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

I'll give you one more reason, why to implement parent-first: you reduce the amount of classes loaded in perm memory. Imagine you have multiple web applications using the same library. With parent-first the library with be loaded once. With parent-last it will be loaded multiple times.
However, with parent-first all web-apps will be required to use the same version of the library, while with parent-last they may use different versions.

我再给你一个理由,为什么要实现父级优先:你减少加载在永久内存中的类的数量。假设您有多个 Web 应用程序使用同一个库。使用 parent-first 将加载一次库。使用 parent-last 它将被加载多次。
但是,在父优先的情况下,所有网络应用程序都需要使用相同版本的库,而在父优先的情况下,它们可能会使用不同的版本。

回答by Brian Roach

Not really. In fact it's as simple as instantiating an URLClassLoaderand giving it nullfor the parent:

并不真地。事实上,它就像实例化 anURLClassLoader并将其null提供给父级一样简单:

myClassLoader = new URLClassLoader(myUrlArray, null);

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

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

回答by Karthik Ramachandran

The only other reason I can think of would be to ensure that the classpath works as expected. By searching the parent first you are in effect putting the parent's classpath (i.e. the system classpath ) before the child's classpath. So if you specify specific jars when you start the jvm using -cp they would "shadow" any jars you've included in any archive that your trying to load. If you don't check the parent first then the child's class path would shadow the parent.

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

回答by irreputable

Tarlog is correct, you don't have to do it that way. Java didn't envision use case like tomcat.

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

However it is questionable why containers host multiple apps in one VM. Separate processes is nicer.

然而,为什么容器在一个 VM 中托管多个应用程序是有问题的。单独的进程更好。

回答by puppylpg

Tomcat web application class loader doesn't obey "use parent first". As mentioned in docs:

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

As mentioned above, the web application class loader diverges from the default Java delegation model (in accordance with the recommendations in the Servlet Specification, version 2.4, section 9.7.2 Web Application Classloader). When a request to load a class from the web application's WebappX class loader is processed, this class loader will look in the local repositories first, instead of delegating before looking. There are exceptions. Classes which are part of the JRE base classes cannot be overridden.

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

回答by Jonathan

If you do not search your parent at all, you will lose access to all of the standard Java objects, and likely will not be able to run at all.

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

But it is reasonable to search your own classloader first, before trying the parent. If you want to override behavior that a class above you provides, you would need to do it this way.

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

The JVM doesn't, because searching your parent first makes the most sense. If you know what you're doing, though, you can do some pretty interesting stuff with class loaders. Take a look at Classworlds.

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