上一篇博文说明了 java中 class.getResource(String name) 与 classloader.getResource(String name) 中name参数的一些事。
今天来分析下类加载器是怎么加载指定资源的,即classloader.getResource(String name)方法。
先来看下源码:
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)会让父类去加载,父类找不到再通过子类自身findResource(name)方法来找资源,来看下findResource(name)方法的源码,方法定义在appclassloader的父类urlclassloader里面,
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;
}
ucp即URLClassPath类,这个类是个关键类,这个类看懂一般就没有问题了,在来看一下URLClassPath里面的findResource(name)方法
public URL findResource(String name, boolean check) {
Loader loader;
for (int i = 0; (loader = getLoader(i)) != null; i++) {
URL url = loader.findResource(name, check);
if (url != null) {
return url;
}
}
return null;
}
URLClassPath类里面有三个loader类,Loader 本身, jarLoader, fileLoader 三个加载类用于加载不同位置的资源,
Loader 作为父类一般用来加载网络资源,
jarLoader 用来加载jar包内的资源,
fileLoader用来加载本地路径下的资源
每个loader实现不一样,细节自己看源码哦!
现在来看一个现象:
新建一个java 项目, 里面只有一行可以执行代码
public static void main(String[] args) throws Exception {
System.out.println(DemoConfig.class.getResource("/WebRoot"));
}
将该项目打成一个jar包,然后往里面塞进一个 WebRoot目录, 执行 java -jar ...命令
jar包内目录结构如下:
执行后输出的结果如下:
但是如果你把WebRoot目录放到jar包同层目录,结果又不一样
同层结构如下:
结果如下:
原因大家看了文章应该能理解点