简体   繁体   English

如果重复,Java中的Classloader如何知道要加载哪个文件资源?

[英]How does the Classloader in Java know which file resource to load if there are duplicates?

I apologize in advance if the answer to this question is a simple one. 如果对此问题的答案很简单,我预先表示歉意。 It seems I don't have enough knowledge about classloading in Java. 似乎我对Java中的类加载没有足够的了解。

Say I have a file called "properties" in my application. 假设我的应用程序中有一个名为“ properties”的文件。 My application uses an external JAR and inside that JAR, there's also a file called "properties". 我的应用程序使用外部JAR,并且在该JAR内部,还有一个名为“ properties”的文件。

Question: 题:

If the external JAR file attempts to open that file with getClass().getClassLoader().getResourceAsStream("properties") , why doesn't it load the one from my application. 如果外部JAR文件尝试使用getClass().getClassLoader().getResourceAsStream("properties")打开该文件,为什么不从我的应用程序中加载该文件。 Not that I want it to, but wouldn't the ClassLoader in this case be the one that loaded my application? 不是我想要它,但是在这种情况下ClassLoader不会成为加载我的应用程序的那个吗? I thought that method would use the absolute path for finding the resource. 我认为该方法将使用绝对路径来查找资源。 Do classes in external JARs get loaded with a different classloader? 外部JAR中的类是否使用其他类加载器加载?

The class loading mechanism is the same for classes and resources (but the bytes found are treated differently). 对于类和资源,类加载机制是相同的(但是所找到的字节将被不同地对待)。

See http://docs.oracle.com/javase/tutorial/ext/basics/load.html for the official explanation. 有关正式说明,请参见http://docs.oracle.com/javase/tutorial/ext/basics/load.html

It is the first class loader actually asked which has the resource that wins. 实际询问的是一流的装载机,它具有赢得资源。 If the class loader does not have its resource, try again with the parent. 如果类加载器没有资源,请与父级一起重试。

(Note that for web applications - WAR files - this is deliberately slightly different about which one is asked first). (请注意,对于Web应用程序-WAR文件-故意在先询问哪个方面略有不同)。

No, it loads the first found in that class' classloader. 不,它将加载在该类的类加载器中找到的第一个。 If you want to open a file using an absolute path, you open an InputStream pointing at the file. 如果要使用绝对路径打开文件,请打开一个指向该文件的InputStream Classes in external JAR might be loaded using different classloaders (eg in a Java EE container) but then classloaders need to be chained in order for you to see them. 可以使用不同的类加载器(例如,在Java EE容器中)加载外部JAR中的类,但是随后需要链接类加载器,以便您查看它们。

Th ClassLoader#getResourceAsStream(String) calls getResource(String) and this as getResource() on the parent. ClassLoader#getResourceAsStream(String)调用父对象的getResource(String)并将其作为getResource()。 If this does not find anything, then it will ask the classloaders findResource(String) . 如果找不到任何东西,它将询问类加载器findResource(String)

It depends on this implementation what it does return, in case of the URLClassLoader this will be URLClassPath.findResource() which steps through all loaders (one loader for each search path entry) and returns the first find. 它取决于此实现的返回结果,如果是URLClassLoader它将是URLClassPath.findResource() ,它逐步遍历所有加载程序(每个搜索路径条目一个加载程序)并返回第一个查找结果。

In a normal application your JARs as well as all libraries are loaded by the same (Application) class loader. 在普通应用程序中,您的JAR和所有库都由相同的(应用程序)类加载器加载。 In case of the Sun launcher this is sun.misc.Launcher$AppClassLoader which extends URLClassLoader . 对于Sun启动器,它是sun.misc.Launcher$AppClassLoader ,它扩展了URLClassLoader It puts all JAR and classes from the classpath in the search list. 它将来自类路径的所有JAR和类放入搜索列表。

It is a good idea to make resources either unique (putting them in your packages) or retrieve all resources and pick the right one (or all). 最好使资源具有唯一性(将其放入程序包中)或检索所有资源并选择正确的一个(或全部)资源。 The later is for example used by the ServiceLoader when it finds all implementations for a given service. 例如,后者在ServiceLoader查找给定服务的所有实现时使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM