Class.getResource和ClassLoader.getResource的区别分析
程序员文章站
2022-05-27 15:11:06
...
Class.getResource
实现原理
使用加载当前类的类加载器加载指定资源;
使用说明
- path不以’/’开头时,以类所在的包路径为基准路径获取资源;
- path以’/’开头时,以ClassPath为基准路径获取资源;
代码实现
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);
}
ClassLoader.getResource
实现原理
双亲委派模型:首先委托父类加载器加载资源,如果找不到则调用自身findResource方法进行加载;
代码实现
public URL getResource(String name) {
URL url;
if (parent != null) {
url = parent.getResource(name);
} else {
url = getBootstrapResource(name);
}
if (url == null) {
url = findResource(name);
}
return url;
}
示例说明
以AppClassLoader的实现逻辑为例进行说明。AppClassLoader继承URLClassLoader,创建实例时将classpath作为URL,如下图所示:
findResource逻辑继承自URLClassLoader,权限校验之后从指定URL路径获取资源,如下图所示:
public URL findResource(final String name) {
/*
* The same restriction to finding classes applies to resources
*/
URL url = AccessController.doPrivileged(
new PrivilegedAction<URL>() {
public URL run() {
return ucp.findResource(name, true);
}
}, acc);
return url != null ? ucp.checkURL(url) : null;
}
二者关联
关联逻辑: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;
}
示例说明
从上面的逻辑可以看出,class.getResource(“/”) == class.getClassLoader().getResource(“”),如下图所示:
参考:
下一篇: 如何切换IDEA的运行时JDK