问题一:
ClassLoader.getSystemResource("img.png");
完全一样,有ClassLoader.getSystemClassLoader().getResource("img.png");
什么区别(更喜欢哪一个?)。我期待答案“两者都不使用”(在应用程序服务器内),那么我们在 API 中有这些方法是为了什么?
问题二:
将我的 WAR/应用程序放在 Tomcat/其他 AppServer 中,我是否应该总是使用Thread.currentThread().getContextClassLoader().getResourceAsStream("img.png")
而不考虑其他更合适的用例(例如,objOfMyOwnClassCreatedAnywhereWithinMyApp.getClass().getClassLoader().getResource("sth")
?
总结一下我知道的:
ClassLoader.getSystemResource("img.png");
对比
ClassLoader.getSystemClassLoader().getResource("img.png");
对比
Thread.currentThread().getContextClassLoader().getResource("sth");
My.class.getClassLoader().getResource("sth");
obj.getClass().getClassLoader().getResource("sth");
obj.getClass().getClassLoader().getSystemClassLoader().getResource("sth");
My.class.getClass().getClassLoader().getSystemClassLoader().getResource("sth");
我的理解是否正确:
1)在任何应用程序服务器(包括 Tomcat)中,我将只使用Thread.currentThread().getContextClassLoader().getResourceAsStream("NoSlash!_Img.png");
1.1)我永远不会使用其余的任何东西(在任何应用服务器上)
2)在桌面应用程序上,以上所有内容都是等效的
3) Tomcat 本身(包含 main() 的类 - Tomcat 的入口点)使用系统类加载器加载 - 始终可以(100%?)被识别为ClassLoader.getSystemClassLoader()
我System.setProperty("java.system.class.loader")
不清楚什么。此外,obj.getClass().getClassLoader().getSystemClassLoader()
也应返回与 相同ClassLoader.getSystemClassLoader()
,但它可能会返回null
(如果自定义类加载器的实现者决定他们最好不要公开系统类加载器)。除了 null 和真正的 System ClassLoaderobj.getClass().getClassLoader().getSystemClassLoader()
可能不会返回任何其他内容(因为返回一些其他类加载器会很愚蠢?)。
4) Tomcat / 另一个应用程序服务器中的任何 Web 应用程序 (= context = WAR) 都使用其单独的(自定义)类加载器(有时称为“应用程序类加载器”,这将其与“系统类加载器”混淆,有时也称为“应用程序类加载器”)。如果我在 A 类方法中,调用this.getClass().getClassLoader()
会为我提供(自定义)类加载器,它加载了我的 A 类(以及我的整个 WAR / 应用程序)。
那么我为什么要使用Thread.currentThread().getContextClassLoader().getResource("sth")
而不是this.getClass().getClassLoader().getResource("sth")
呢?我认为最好使用我的 WAR 自定义类加载器!
上下文类加载器在我的 WAR 的所有线程中是否始终相同(除非我自己启动线程并弄乱上下文类加载器)并且与加载我的 WAR(objOfMyOwnClassesCreatedAnywhereWithinMyApp.getClass().getClassLoader()
)的自定义类加载器相同?
PS这里的答案意味着我更喜欢使用上下文类加载器的一种情况。这意味着在许多其他情况下不使用上下文类加载器是可以的(当在我的线程上创建的对象没有提供给任何其他线程时,尤其是没有由我创建的其他线程时)。
每个类都将使用自己的类加载器来加载其他类。因此,如果 ClassA.class 引用 ClassB.class 那么 ClassB 需要位于 ClassA 的类加载器或其父级的类路径上。
线程上下文类加载器是当前线程的当前类加载器。可以从 ClassLoaderC 中的类创建对象,然后将其传递给 ClassLoaderD 拥有的线程。 在这种情况下,对象需要直接使用 Thread.currentThread().getContextClassLoader()如果它想加载它自己的类加载器上不可用的资源。
除了这里的 Stackoverflow 答案(@yonran)建议:
永远不要使用上下文类加载器!