之间有什么区别
getClass().getResource("some-resource-file.txt")
vs
Thread.currentThread().getContextClassLoader().getResource("some-resource-file.txt")
我在src / test / resources&中有资源。我试图从单元测试中访问它们。这是典型的maven样式目录结构。
我期待两者都表现得相同。但它不是。,getClass()。getResource()不会获取资源,而是从线程中我可以获取资源。
那他们有什么不同?
答案 0 :(得分:4)
我们假设您正在开发一个库,并且库jar被放入一个Web容器的类路径中。
现在让我们说使用此库的webapp部署在容器中。
webapp将拥有自己的类加载器,使用WEB-INF / classes和WEB-INF / lib / * .jar作为其类路径。对于每个进入webapp的请求,容器都会将当前线程类加载器设置为类路径的类加载器。
当您的库代码使用getClass().getResource()
时,它将使用用于加载库类的类加载器加载资源。因此它将使用容器的类加载器,因此将使用库的jar和用于启动容器的其他库中的资源。
如果您的库代码使用Thread.currentThread().getContextClassLoader()
来加载资源,它将使用与当前线程关联的类加载器,并因此从webapp的类加载器加载资源,寻找资源在WEB-INF / classes和WEB-INF / lib中的jar中。
后者可以是你想要的。例如,如果您正在设计日志库(请不要),则记录器将能够为每个Web应用程序读取不同的配置文件,而不是所有Web应用程序共享一个配置文件。 / p>
关于两种方法查找资源的方式,它们最终都委托给一个ClassLoader来加载资源。但是通过Class加载它会将相对路径视为相对于被调用类,而通过ClassLoader加载它需要从包树的根开始的路径。假设您的班级在com.foo
包中,然后是
MyClass.class.getResource("hello.txt")
相当于
MyClass.class.getResource("/com/foo/hello.txt")
并且相当于
MyClass.class.getClassLoader().getResource("com/foo/hello.txt");
答案 1 :(得分:2)
有一个特殊情况让第一个类运行(这就是为什么你必须将main()方法声明为static,并将一个字符串数组作为参数)。
一旦加载并运行该类,将来加载类的尝试将由类加载器完成。最简单的是,类加载器创建一个由字符串名称引用的类主体的平面名称空间。 Java中的每个类都使用自己的类加载器来加载其他类。因此,如果ClassA.class
引用ClassB.class
,则ClassB
需要位于ClassLoader
ClassA
或其父级的类路径上。
线程上下文ClassLoader
是一个特殊的,它是当前正在运行的线程的当前ClassLoader
。这在多类加载器环境中很有用。可以从ClassLoader C
中的类创建对象,然后将其传递给ClassLoader D
拥有的线程。在这种情况下,如果对象需要加载其自身Thread.currentThread().getContextClassLoader()
不可用的资源,则需要直接使用ClassLoader
。