我想知道Class.getResource()和ClassLoader.getResource()之间的区别是什么?

编辑:我特别想知道文件/目录级别是否涉及缓存。如“目录列表是否缓存在类版本中?”

我认为下面这些应该做同样的事情,但它们不是:

getClass().getResource() 
getClass().getClassLoader().getResource()

我在摆弄一些报告生成代码时发现了这一点,这些代码从WEB-INF/classes/目录中的现有文件创建了一个新文件。当使用来自Class的方法时,我可以使用getClass(). getresource()找到部署时存在的文件,但当试图获取新创建的文件时,我收到了一个空对象。浏览目录会清楚地显示新文件在那里。文件名以斜杠开头,如"/myFile.txt"。

另一方面,getResource()的ClassLoader版本确实找到了生成的文件。从这个经验来看,似乎有某种目录列表的缓存正在进行。我说得对吗?如果是的话,这在哪里有记录?

来自Class.getResource()上的API文档

寻找资源 有一个名字。的规则 查找关联的资源 类实现 定义类的类装入器。 此方法委托给该对象的方法 类装入器。如果这个对象是 由引导类装入器装入, 方法委托给 ClassLoader.getSystemResource(以)。

对我来说,这就是“阶级”。getResource实际上是调用它自己的类加载器的getResource()”。这将与执行getClass(). getclassloader (). getresource()相同。但事实显然并非如此。有人能给我一些关于这件事的说明吗?


当前回答

另一种更有效的方法是使用@Value

@Value("classpath:sss.json")
private Resource resource;

然后你就可以这样获取文件了

File file = resource.getFile();

其他回答

类。getResource可以接受一个“相对”资源名,它相对于类的包进行处理。或者,您可以使用前导斜杠指定“绝对”资源名。类加载器资源路径总是被认为是绝对的。

所以下面这些基本是等价的:

foo.bar.Baz.class.getResource("xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("foo/bar/xyz.txt");

这些也是(但它们与上面的不同):

foo.bar.Baz.class.getResource("/data/xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("data/xyz.txt");

第一个调用相对于.class文件进行搜索,而后一个调用相对于类路径根进行搜索。

为了调试这样的问题,我打印了URL:

System.out.println( getClass().getResource(getClass().getSimpleName() + ".class") );

我查了一下说明书

类。getResource(字符串资源) 类加载器。getResource(字符串资源)

类的getResource() -文档说明了区别:

这个方法将调用委托给它的类加载器,在对资源名进行这些更改之后:如果资源名以“/”开头,则资源名不变;否则,在将“。”转换为“/”后,包名将放在资源名之前。如果该对象是由引导加载器加载的,则调用将委托给ClassLoader.getSystemResource。

我试着从input1.txt中读取,它在我的一个包中,和试图读取它的类一起。

以下工作:

String fileName = FileTransferClient.class.getResource("input1.txt").getPath();

System.out.println(fileName);

BufferedReader bufferedTextIn = new BufferedReader(new FileReader(fileName));

最重要的部分是调用getPath(),如果您想要字符串格式的正确路径名。不要使用toString(),因为它会添加一些额外的格式文本,这将完全混乱的文件名(你可以尝试一下,看看打印出来)。

花了2个小时调试这个…:(

这里所有这些答案,以及这个问题的答案,都建议加载绝对url,比如“/foo/bar”。class.getResourceAsStream(String)和class.getClassLoader(). getresourceasstream (String)处理相同。但事实并非如此,至少在我的Tomcat配置/版本(当前为7.0.40)中不是这样。

MyClass.class.getResourceAsStream("/foo/bar.properties"); // works!  
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work!

抱歉,我绝对没有令人满意的解释,但我猜tomcat对类加载器做了肮脏的把戏和他的黑魔法,导致了差异。我总是使用class.getResourceAsStream(String)在过去,没有任何问题。

PS:我也把这个贴在这里了