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=.