虽然网上关于ClassLoader和Class的getResource()和getResourceAsStream()方法的区别多的数不胜数,但是自己也遇到了这个问题,所以就记录了下来。
背景:昨日由于项目中要使用ehcache缓存,所以本人新建了个Java Project。写个ehcache缓存对象的demo,于是在网上找了个例子,第一步是
CacheManager cacheManager = CacheManager.getInstance();
Cache cache = cacheManager.getCache(cacheName);
看完第一行代码感觉非常好奇。我的ehcache.xml放到src下,CacheManager.getInstance()时是怎么加载ehcache.xml的,于是打开ehcache的源码,发现在最后是有解析ehcache.xml的代码,如下图:
由上图可以看到ehcache在找ehcache.xml的时候默认是先使用ClassLoader.getResource(),如果用ClassLoader的方式获取的Url为null的话,再使用Class.getResource(),但是ClassLoader的getResource()方法和Class的getResource()方法到底有什么区别呢?于是自己分别用这两种方式去测试(我新建的Java项目,默认classes文件在项目下/bin/下,ehcache.xml在src下)。
测试代码如下:
URL resource = Thread.currentThread().getContextClassLoader().getResource("ehcache.xml");
System.out.println(resource);
System.out.println("-------------------------");
InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("ehcache.xml");
System.out.println(resourceAsStream);
System.out.println("-------------------------");
InputStream resourceAsStream1 = Test.class.getClassLoader().getResourceAsStream("ehcache.xml");
System.out.println(resourceAsStream1);
System.out.println("-------------------------");
URL resource2 = Test.class.getResource("/ehcache.xml");
System.out.println(resource2);
System.out.println("-------------------------");
InputStream resourceAsStream2 = Test.class.getResourceAsStream("/ehcache.xml");
System.out.println(resourceAsStream2);
System.out.println("-------------------------");
结果输出:
file:/E:/MyEclipse/MyEclipse4Spring2013WorkSpace/workspace/cacheTest/bin/ehcache.xml
-------------------------
java.io.BufferedInputStream@40a0dcd9
-------------------------
java.io.BufferedInputStream@1034bb5
-------------------------
file:/E:/MyEclipse/MyEclipse4Spring2013WorkSpace/workspace/cacheTest/bin/ehcache.xml
-------------------------
java.io.BufferedInputStream@7f5f5897
-------------------------
以上用ClassLoader和Class方式的getResource()和getResourceAsStream()方法都能找到ehcache.xml文件。但是仔细观察你会发现,ClassLoader的getResource()和getResourceAsStream()方法中的参数都不带"/",而Class方式的都带“/”。如果ClassLoader方式的加上"/"的话,会无法找到,Class方式的去掉"/"的话也不能找到。(可自行测试)
另附上不加任何文件名的方式测试:
System.out.println(Test.class.getResource("/"));
System.out.println(Test.class.getResource(""));
System.out.println(Test.class.getClassLoader().getResource(""));
System.out.println(Thread.currentThread().getContextClassLoader().getResource(""));
结果:
file:/E:/MyEclipse/MyEclipse4Spring2013WorkSpace/workspace/cacheTest/bin/
file:/E:/MyEclipse/MyEclipse4Spring2013WorkSpace/workspace/cacheTest/bin/com/cache/test/
file:/E:/MyEclipse/MyEclipse4Spring2013WorkSpace/workspace/cacheTest/bin/
file:/E:/MyEclipse/MyEclipse4Spring2013WorkSpace/workspace/cacheTest/bin/
结论:
1、ClassLoader的getResource()和getResourceAsStream()方法找的是classpath根目录下的resource(注意不能带"/")。
2、Class的getResource()和getResourceAsStream()方法不带"/"的话找到的是当前类的同目录路径。带上"/"的话找到的是classpath根目录路径。
PS:Test.class.getProtectionDomain().getCodeSource().getLocation().getPath(); 这样也可以获取到classpath的绝对路径。