obj.getClass().getResourceAsStream() 和 obj.getClass().getClassLoader().getResourceAsStream() 资源路径差别
在学习过程中,将部分配置信息放在 properties 文件中,代码中读取时碰到 obj.getClass().getResourceAsStream() 无法加载资源,而 obj.getClass().getClassLoader().getResourceAsStream() 可以正常加载资源。
作为初学者,对于其中的区别还没有反应过来,先使用后者把代码跑起来。后来查了资料后,对两者的差别才有些基本了解。
这里记录两者的差别和各自使用注意点:
- obj.getClass().getResourceAsStream():如果资源路径不是以
/开头,则根据当前类的包路径作为相对路径进行资源加载;如果资源路径以/开头,则从 classpath 加载资源;使用时注意资源和当前类的相对路径。 - obj.getClass().getClassLoader().getResourceAsStream():只从 classpath 加载资源。
查到资料后就准备查看代码逻辑是怎么实现的,这里把 obj.getClass().getResourceAsStream() 的代码中对资源路径的处理方法摘录下来。
进入方法先对路径进行处理:
public InputStream getResourceAsStream(String name) {
name = resolveName(name);
Module thisModule = getModule();
if (thisModule.isNamed()) {
// check if resource can be located by caller
if (Resources.canEncapsulate(name)
&& !isOpenToCaller(name, Reflection.getCallerClass())) {
return null;
}
// resource not encapsulated or in package open to caller
String mn = thisModule.getName();
ClassLoader cl = classLoader;
try {
// special-case built-in class loaders to avoid the
// need for a URL connection
if (cl == null) {
return BootLoader.findResourceAsStream(mn, name);
} else if (cl instanceof BuiltinClassLoader) {
return ((BuiltinClassLoader) cl).findResourceAsStream(mn, name);
} else {
URL url = cl.findResource(mn, name);
return (url != null) ? url.openStream() : null;
}
} catch (IOException | SecurityException e) {
return null;
}
}
// unnamed module
ClassLoader cl = classLoader;
if (cl == null) {
return ClassLoader.getSystemResourceAsStream(name);
} else {
return cl.getResourceAsStream(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.startsWith("/")) {
String baseName = getPackageName();
if (!baseName.isEmpty()) {
int len = baseName.length() + 1 + name.length();
StringBuilder sb = new StringBuilder(len);
name = sb.append(baseName.replace('.', '/'))
.append('/')
.append(name)
.toString();
}
} else {
name = name.substring(1);
}
return name;
}
从代码中可以看出,obj.getClass().getResourceAsStream() 对路径的处理,和相对路径的拼接。
问题是小问题,通过在 jdk 的代码中翻出了实现逻辑,加深了理解,但是知道的越多,不知道的就越多,类加载器、模块(Module)诸多概念等学习到了再看。
到此,本篇记录结束。
浙公网安备 33010602011771号