文档章节

Class#getResource与ClassLoader#getResource分析

叶易
 叶易
发布于 2016/08/09 17:07
字数 814
阅读 51
收藏 0
  • Class#getResource方法的参数path可以与以'/'开头的绝对路径或是不以'/'开头的相对路径,当以'/'开头时,会从classpath路径下获取资源,当不以'/'开头时,则从该类所在的包下获取资源,xxx.class.getResource() 即xxx.class类所在包。
  • 而ClassLoader#getResource方法的参数却不能以'/'开头,其是从classpath下面获取资源。

来看看下面代码的结果

package com.jdk.resource;
public class Resource {
	 public static void main(String[] args) throws Exception {
	        System.out.println(Resource.class.getResource(""));
	        System.out.println(Resource.class.getResource("/"));
	        System.out.println(Resource.class.getClassLoader().getResource(""));
	        System.out.println(Resource.class.getClassLoader().getResource("/"));
	    }
}

结果:

file:/D:/workspace/JDKCore/bin/com/jdk/resource/
file:/D:/workspace/JDKCore/bin/
file:/D:/workspace/JDKCore/bin/
null

可以看到Resource.class.getResource("")得到的路径classpath下Resource 类所在包,而Resource.class.getResource("/")为classpath根路径;而Resource.class.getClassLoader().getResource("")同样为classpath根路径,Resource.class.getClassLoader().getResource("/")则为空。 下面来看看Class#getResource方法的源码

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);
   }

从 cl.getResource(name)一行可以看出,Class#getResource方法最终还是调用了CalssLoader#getResource方法。再来看看name = resolveName(name)的实现,做了什么处理,其调用了Class类的resolveName方法

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;
    }

可以看出,resolveName方法的目的是当参数name以'/'开头就将'/'去除再返回,而当不以'/'开头则根据这个类对应的带包名全称变换成具体的路径名,如com.jdk.resource替换成com/jdk/resource。

现在应该明白最开始那个Resource 类中main方法的结果,实际上Class#getResource方法是去调CalssLoader#getResource的方法,只是在调用时会去判断是从相对路径还是绝对路径获取资源。不过api是有一点点坑Class#getResource以'/'开头与ClassLoader#getResource相同,再记住ClassLoader#getResource不能以'/'开头就行了。

有了前面这个Classr#getResource与ClassLoader#getResource的对比,Class#getResourceAsStream与ClassLoader#getResourceAsStream其实也就ok了。

Class#getResourceAsStream源码:

public InputStream getResourceAsStream(String name) {
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResourceAsStream(name);
        }
        return cl.getResourceAsStream(name);
    }

ClassLoader#getResourceAsStream源码:

public InputStream getResourceAsStream(String name) {
        URL url = getResource(name);
        try {
            return url != null ? url.openStream() : null;
        } catch (IOException e) {
            return null;
        }
    }

所以,可以用下面三种方式得到资源

  1. 利用Class#getResourceAsStream方法根据绝对路径从classpath下面得到,参数path以'/'开头
  2. 利用Class#getResourceAsStream方法根据类所处包的相对路径得到,参数path不能以'/'开头
  3. 利用ClassLoader#getResourceAsStream方法根绝对路径从classpath下面得到,参数path不能以'/'开头

在com.jdk.resource目录下创建一个test.properties文件,可以用以下三种方式得到

package com.jdk.resource;
public class Resource {
	 public static void main(String[] args) throws Exception {
		    //第一种方式
		    System.out.println(Resource.class.getResourceAsStream("test.properties"));
		    //第二种方式
		   System.out.println(Resource.class.getResourceAsStream("/com/jdk/resource/test.properties"));
		    //第三种方式
	System.out.println(Resource.class.getClassLoader().getResourceAsStream("com/jdk/resource/test.properties"));
	    }
}

结果:

java.io.BufferedInputStream@659e0bfd
java.io.BufferedInputStream@2a139a55
java.io.BufferedInputStream@15db9742

这对查看,Spring Resource 接口的实现ClassPathResource类getInputStream方法有一定帮助

public InputStream getInputStream() throws IOException {
		InputStream is;
		if (this.clazz != null) {
			is = this.clazz.getResourceAsStream(this.path);
		}
		else if (this.classLoader != null) {
			is = this.classLoader.getResourceAsStream(this.path);
		}
		else {
			is = ClassLoader.getSystemResourceAsStream(this.path);
		}
		if (is == null) {
			throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
		}
		return is;
	}

© 著作权归作者所有

共有 人打赏支持
叶易
粉丝 22
博文 24
码字总数 30959
作品 0
无锡
私信 提问
Java 加载资源文件

简介 Java中获取资源的最常用的2中方式就是使用Class的getResource和使用ClassLoader的getResource方法,当然还有它们相关的方法。这里就介绍一下使用这2中方式的区别,和它们搜索使用的路径...

trayvon
2016/12/03
53
0
你务必要搞清楚的六大数据分析知识点

一、数据分析是神马 1. 何谓数据分析 用适当的统计分析方法和相应工具,对收集来的大量数据进行详细研究和概括总结,提取有用信息和形成结论,这一过程叫做数据分析。 数据分析有广义和狭义之...

柯西带你学编程
05/22
0
0
Teradata天睿推出更强大的Teradata分析平台

  【IT168 资讯】全球数据和分析解决方案供应商Teradata天睿公司(Teradata Corporation,纽交所:TDC)宣布推出Teradata分析平台(Teradata Analytics Platform)。新平台交付用户使用最优秀的...

it168网站
2017/11/27
0
0
云计算下性能优化-读《性能之巅》

性能之巅的全名《性能之巅-洞悉系统、企业与云计算》,英文名《Systems performance: Enterprise and the Cloud》。讲述Linux和unix在云计算下的性能,以及如何分析改进系统性能。本书有理论...

通爸
04/12
0
0
最常用的四种数据分析方法

本文主要讲述数据挖掘分析领域中,最常用的四种数据分析方法:描述型分析、诊断型分析、预测型分析和指令型分析。 当刚涉足数据挖掘分析领域的分析师被问及,数据挖掘分析人员最重要的能力是...

powertoolsteam
2017/09/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Netty handle方法周期 (四)

写了一个练习之后,发现自定义的助手类每次肯定是必须的,对于不同的业务逻辑需求,会写相对应的逻辑 最简单的查看Handle生命周期的方式,就是重写上级方法,看名字差不多应该可以知道方法的作用 ...

_大侠__
5分钟前
0
0
vue主动刷新页面及列表数据删除后的刷新实例

1.场景 在处理列表时,常常有删除一条数据或者新增数据之后需要重新刷新当前页面的需求。 2.遇到的问题 1. 用vue-router重新路由到当前页面,页面是不进行刷新的 2.采用window.reload(),或者...

前端小攻略
15分钟前
0
0
闲话高并发的那些神话,看京东架构师如何把它拉下神坛

高并发也算是这几年的热门词汇了,尤其在互联网圈,开口不聊个高并发问题,都不好意思出门。高并发有那么邪乎吗?动不动就千万并发、亿级流量,听上去的确挺吓人。但仔细想想,这么大的并发与...

James-
21分钟前
1
0
Emacs 系列:让我们拥抱 Emacs 和 org 模式

导读 我必须承认,在使用了几十年的 vim 后, 我被 Emacs 吸引了。长期以来,我一直对如何组织安排事情感到沮丧。我也有用过 GTD 和 ZTD 之类的方法,但是像邮件或是大型文件这样的事务真的很...

问题终结者
22分钟前
2
0
解析Node.js通过axios实现网络请求

本次给大家分享一篇node.js通过axios实现网络请求的方法,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。 1、使用Npm 下载axios n...

前端攻城老湿
35分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部