一、问题引入
最近使用如下方式载入配置文件时总是返回null
:
Thread.currentThread().getContextClassLoader().getResource("config.properties")
配置文件说明:
config.properties
文件放置在与src
目录同级的config
目录中。
二、问题分析
查看API文档发现关于类ClassLoader方法getResource
的返回值有如下描述:
读取资源的 URL 对象;如果找不到该资源,或者调用者没有足够的权限获取该资源,则返回 null。
由文档API可知,返回null有两种原因引起:
- 找不到该资源;
- 对该资源没有获取权限。
这里显然可以排除第2中原因,那么明明config/config.properties文件存在,为什么会找不到呢?
原因和Java Resource资源载入路径有关。
默认情况下,Java在载入资源时,只会在工程的classpath
下寻找。
这里需要说明的是对classpath的认识不要局限在只是在这里寻找二进制class文件、jar包,Java还会在这里寻找文本文件(例如配置文件),图像,声音资源等。
为了一探究竟,我们打印出classpath,可以通过如下两种方式:
获取属性
java.class.path
:System.getProperty("java.class.path")
利用如下代码段:
ClassLoader classLoader = ClassLoader.getSystemClassLoader(); //Get the URLs URL[] paths = ((URLClassLoader)sysClassLoader).getURLs(); for(int i=0; i< paths.length; i++) { System.out.println(paths[i].getFile()); }
以上两种方式,得到的classpath
结果相同:
/Users/zq/Documents/workspace/yourProjectName/bin/
/Users/zq/Documents/workspace/yourProjectName/lib/ant.jar
/Users/zq/Documents/workspace/yourProjectName/lib/commons-logging-1.0.4.jar
/Users/zq/Documents/workspace/yourProjectName/lib/log4j-1.2.9.jar
/Users/zq/Documents/workspace/yourProjectName/lib/mysql-connector-java-5.1.33-bin.jar
/Users/zq/Documents/workspace/yourProjectName/lib/httpclient-4.3.1.jar
/Users/zq/Documents/workspace/yourProjectName/lib/httpcore-4.3.jar
/Users/zq/Documents/workspace/yourProjectName/lib/commons-codec-1.6.jar
/Users/zq/Documents/workspace/yourProjectName/lib/commons-lang-2.6.jar
/Users/zq/Documents/workspace/yourProjectName/lib/mail-1.4.5.jar
/Users/zq/Documents/workspace/yourProjectName/lib/trove-3.0.0a6.jar
其中可以看出classpath
中并没有包含config/config.properties
。
三、问题解决
到目前为止,问题的原因已经搞清楚了,那么问题的解决也就迎刃而解了:
只要把config/config.properties
添加到工程的build path
中即可。
再次打印出classpath
,可以看到最后一行已经包含了config
目录:
······
/Users/zq/Documents/workspace/yourProjectName/lib/commons-lang-2.6.jar
/Users/zq/Documents/workspace/yourProjectName/lib/mail-1.4.5.jar
/Users/zq/Documents/workspace/yourProjectName/lib/trove-3.0.0a6.jar
/Users/zq/work_xxx/yourProjectName/config/
四、深入探究
在Java工程中,获取资源一般通过如下两种方式(相应的getResourceAsStream方法返回的是同一资源的流形式inputstream):
Class.getResource()
ClassLoader.getResource()
ClassLoader的获取: 1. Thread.currentThread().getContextClassLoader() 2. clazz.getClassLoader() 3. ClassLoader. getSystemClassLoader()
两者的区别为:第一种方式在相对clazz的路径中寻找资源;第二种方式是在整个classpath中寻找资源。
两者的共同点为:都在classpath
中寻找资源。
最后需要说明的是:
Java中不存在标准的相对路径,各种相对路径取资源的方式都是基于某种规则转化为绝对路劲,但是在编程过程中,绝对不要直接使用绝对路径。
所以,我们在使用Java载入Resource资源时,只要寻找到合适的参考基点,就能很轻松得定位你要找的resource资源,一般情况下参考基点有如下几种:
- classpath:
本博文已经详细的做了介绍,这里不再做赘述。 当前工程目录(强烈不推荐使用,会带来移植问题)
System.getProperty("user.dir")
- Web应用程序的根目录
在Web应用程序中,一般通过ServletContext.getRealPath("/" )
方法得到Web应用程序的根目录的绝对路径。
五、参考链接:
http://blog.csdn.net/cutesource/article/details/6141768
http://blog.csdn.net/ak913/article/details/7399056