Class.getResourceAsStream和ClassLoader.getResourceAsStream的区别

来源:互联网 发布:人肉是什么味道 知乎 编辑:程序博客网 时间:2024/05/19 11:46

ClassLoader.getResourceAsStream

根据指定的资源名称读取该资源的输入流InputStream

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

可见,真正的加载逻辑在java.lang.ClassLoader#getResource(String name) 方法内,其加载过程也和双亲委派模型保持一致。
BootStrap ClassLoader:/JAVA_HOME/jre/classes目录下
Extension ClassLoader:/JAVA_HOME/jre/lib/ext目录下,并且只能以jar包的形式保存
App ClassLoader:一般当前目录即为加载路径,当然也可以通过java -classpath 或者 java -Djava.class.path 指定

以上自上向下进行查找。

一般我们配合java -cp 指定的路径来实现加载资源的操作。
但是资源也可以放在 jre\classes 目录下:由 BootStrap ClassLoader 进行加载或者使用-Xbootclasspath 或者-Djava.ext.dirs 等等。

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

可以看到,cl.getResourceAsStream(name); 也就是说Class.getResourceAsStream 也是使用 ClassLoader 进行加载的。

resolveName(String name) 方法的作用:

  • 如果是绝对路径则删除前导/
  • 不是绝对路径则添加包名前缀
    事例:对于springmvc.xml(包名为cn.bjut.test),经过该方法返回cn/bjut/test/springmvc.xml

同时这也说明,我们使用ClassLoader.getResourceAsStream 加载资源是不能带有前导 / 字符的。

Class.getResourceAsStream 的恶心之处在于它有个绝对路径相对路径的问题。

测试:
构建如下的目录结构

D:\N3VERL4ND\DESKTOP\COM└─github    │  2.txt    │  B.class    │  B.java    │    └─demo            1.txt            A.class            A.java

A.java

package com.github.demo;public class A {    public static void main(String[] args) {        if (args.length != 1) {            System.out.println("usage: java XXX args");            return;        }        System.out.println(A.class.getResourceAsStream(args[0]));    }}

B.java

package com.github;public class B {    public static void main(String[] args) {        if (args.length != 1) {            System.out.println("usage: java XXX args");            return;        }        System.out.println(B.class.getResourceAsStream(args[0]));    }}

这里写图片描述

对于
InputStream is = A.class.getResourceAsStream(“1.txt”);

路径不是以/开头,说明这是一个相对路径,相对的是A.class这个文件,所以,这里的“1.txt”所指的正确位置是与A.class处于同一目录下的1.txt文件。

文件”1.txt”的绝对路径名为:”/com/github/demo/1.txt” 文件”2.txt”的绝对路径名为:”/com/github/2.txt”
这里写图片描述

其实这里所谓的绝对路径其实是相对于classpath指定的类路径。(不考虑算亲委派模型的情况)
以上测试默认以D:\N3VERL4ND\DESKTOP 为根路径。等效于set classpath=.

阅读全文
0 0
原创粉丝点击