Java工具箱--getResource()

java如何查找资源

Java从“环境”(environment)加载资源,在许多情况下它使用Classpath中的所有jar来检索资源。Java中的资源加载称为位置无关( location independent)是因为它只需要正确的环境来查找资源,与在何处运行代码没有关系。

java将使用资源名称在给定Classpath中以相对路径的方式搜索所有jar和路径,以找到指定的资源。

绝对和相对资源名称

使用资源名称引用资源:getResourceAsStream(“/path/resource.xml”);这里的“/path/resource.xml”是资源名称。
资源名称可以是绝对的,比如“/path/resource.xml”;也可以是相对的,比如“path / resource.xml”;

相对的意思是指相对于方法被调用的位置,在需要的时候文件路径将被附加上。绝对是指路径将被原样使用,只有开头的“/”会被替换掉。

package my.location;

class ResourceFinder {
...
public void findResources(){
//stream1将获取位于类路径中的资源path/resource.xml。
   InputStream stream1 =
getClass().getResourceAsStream("/path/resource.xml");
//stream2将获取位于类路径my/location/path/resource.xml(相对于启动搜索的包的相对资源)的资源。
   InputStream stream2 =
getClass().getResourceAsStream("path/resource.xml");
}
...
}

ClassLoader和Class以不同的方式使用资源名称

ClassLoader.getResource()和Class.getResource()他们的工作方式不同。

Java官方文档中:

ClassLoader中的方法使用给定的字符串作为资源的名称,而不使用任何绝对或相对转换。所以传递给ClassLoader.getResource()的资源名称不应该有一个前导的“/”。所以ClassLoader.getResource(“/”)无法获得任何内容,返回null。

查看JDK源码发现,Class.getResource()将传入的资源名称做了处理后再传给ClassLoader处理。一般在应用代码中Class.getClassLoader0()将获得AppClassLoader,所以getClass().getClassLoader().getResource(‘resource.properties’)基本等同于getClass().getResource(‘/resource.properties’)。

//java.lang.Class

 public java.net.URL getResource(String name) {
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResource(name);
        }
        return cl.getResource(name);
 }
   /**
     * Add a package name prefix if the name is not absolute, 
     * Remove leading "/" if name is absolute
     */
    private String resolveName(String name) {
        if (name == null) {
            return name;
        }
        if (!name.startsWith("/")) {
            Class<?> c = this;
            while (c.isArray()) {
                c = c.getComponentType();
            }
            String baseName = c.getName();
            int index = baseName.lastIndexOf('.');
            if (index != -1) {
                name = baseName.substring(0, index).replace('.', '/')
                    +"/"+name;
            }
        } else {
            name = name.substring(1);
        }
        return name;
    }

而getClass().getResource(‘/resource.properties’)和getClass().getResource(‘resource.properties’)的差异在于getClass().getResource(‘/resource.properties’)在classpath目录下获取resource.properties,getClass().getResource(‘resource.properties’)则在classpath相对于当前类的目录下获取resource.properties。

执行位置与classpath

Java中的资源加载称为位置无关( location independent)是指在在文件系统甚至网络地址的何处运行代码没有关系,在多数情况下Java使用Classpath中的所有jar来检索资源,所以代码执行时的classpath会影响最终执行的效果。
ClassLoader.getResource()在java.class.path和java.library.path路径中遍历寻找资源,如果已经找到就不会继续寻找。由于在不同场景java.class.path引入的路径和顺序不一样,导致在不同场景下ClassLoader.getResource()执行的效果不一样。

比如在Maven工程中, 单元测试的classpath是/target/test-classes/,而应用代码是/target/classes/,getClass().getResource(‘application.properties’)在单元测试和应用代码中访问的分别/target/test-classes/application.properties和/target/classes/application.properties。

JUnit执行时的java.class.path:

java.class.path=C:\work\spring\j2se\target\test-classes;C:\work\spring\j2se\target\classes;C:\java\spring-tool\sts-3.8.0.RELEASE\plugins\org.junit_4.12.0.v201504281640\junit.jar;C:\java\spring-tool\sts-3.8.0.RELEASE\plugins\org.hamcrest.core_1.3.0.v201303031735.jar;C:\Users\david\Desktop\poc_resource.jar;C:\Users\david\.m2\repository\junit\junit\3.8.1\junit-3.8.1.jar;/C:/java/spring-tool/sts-3.8.0.RELEASE/configuration/org.eclipse.osgi/426/0/.cp/;/C:/java/spring-tool/sts-3.8.0.RELEASE/configuration/org.eclipse.osgi/425/0/.cp/

工程main函数执行的java.class.path:

java.class.path=C:\work\spring\j2se\target\classes;C:\java\spring-tool\sts-3.8.0.RELEASE\plugins\org.junit_4.12.0.v201504281640\junit.jar;C:\java\spring-tool\sts-3.8.0.RELEASE\plugins\org.hamcrest.core_1.3.0.v201303031735.jar;C:\Users\david\Desktop\poc_resource.jar

Class.getResource(“.”)与Class.getResource(“/”)

通过Class.getResource(“.”)获取到的文件路径,删除包路径后可以获得classpath。由于getResource的查找方式是基于多个classpath逐一查找命中的资源,所以这中方法得到的classpath可能和Class.getResource(“/”)得到的classpath不一样。

Class.getResource(“/”)得到的是java.class.path的第一个路径,而AnObject.getClass().getResource(“.”)得到的是拥有AnObject的第一个java.class.path。如果我们要查找当前工程路径下的某些资源,需要使用AnObject.getClass().getResource(“.”)定位当前工程的classpath。但如果当前工程是在jar包中执行,常规文件路径定位将无法访问。这时需要使用JarURLConnection或者JarFile定位资源。

扫描指定目录下的类

基于以上分析,下面的方案就比较好理解了。
Java遍历包中所有类-终续:http://blog.csdn.net/wangpeng047/article/details/8206427
以上方法并不能解决包冲突问题,比如有多个classpath都有需要扫描的包com.yourcompany.yourapplication。

利用spring实现package下的类扫描:http://lj3331.blog.51cto.com/5679179/1724896

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值