一,简介
在JDK中,提供了以下方法来获取classpath下的资源:
public abstract class ResourceUtils
{
public static void main(String[] args)
{
test();
}
/**
* @param args
*/
public static void test()
{
String name = "plugins.xml";
System.out.println(null != Thread.currentThread().getContextClassLoader().getResource(name));//相对于classpath根路径
System.out.println(null != Thread.currentThread().getContextClassLoader().getResourceAsStream(name));//相对于classpath根路径
System.out.println(null != ResourceUtils.class.getResource(name));//相对于ResourceUtils.class文件所在包路径。如果name="/plugins.xml"则是相对于classpath根路径
System.out.println(null != ResourceUtils.class.getResourceAsStream(name));//相对于ResourceUtils.class文件所在包路径。如果name="/plugins.xml"则是相对于classpath根路径
}
}
其中ResourceUtils.class.getResource(name),ResourceUtils.class.getResourceAsStream(name)最终还是委托给ClassLoader的getResource和getResourceAsStream去加载资源的。只不过在委托给ClassLoader加载资源之前,对资源的路径进行了一些特殊的处理。
二,ClassLoader资源加载原理
public abstract class ClassLoader {
// The parent class loader for delegation
private ClassLoader parent;
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;
}
}
众所周知,JVM中不同ClassLoader所加载资源的路径是不同的,BootstrapClassloader(根类加载器)资源加载路径为:C:\Program Files\Java\jdk1.7.0_17\jre\lib文件夹。例如:rt.jar,jce.jar等;ExtClassLoader(扩展类加载器)资源加载路径为:C:\Program Files\Java\jdk1.7.0_17\jre\lib\ext文件夹;SystemClassLoader(系统类加载器):应用中编写的class类,引用的第三方jar包均由系统类加载器加载。
由代码中ClassLoader获取资源的优先级可知,如果不同ClassLoader加载的资源路径下存在同名的配置文件或class文件,覆盖顺序为:根类加载器 > 扩展类加载器 > 应用中的资源文件 > 应用所依赖的第三方jar (这也是JVM保证安全性的原则,否则恶意定义一个java.lang.String的类,被JVM加载是不安全的)。
例如:A工程依赖B工程,在B工程中的classpath下有个配置文件plugins.xml,同时在A工程的classpath下也有一个同名的配置文件,那么A工程下的配置文件则会覆盖B下的文件。同样包路径的class文件也会覆盖。
三,Class资源加载原理
public final
class Class<T> implements java.io.Serializable,
java.lang.reflect.GenericDeclaration,
java.lang.reflect.Type,
java.lang.reflect.AnnotatedElement {
public java.net.URL getResource(String name) {
name = resolveName(name);//对name进行路径特殊处理
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResource(name);
}
return cl.getResource(name);//最终还是委托给ClassLoader加载资源
}
/**
* Add a package name prefix if the name is not absolute Remove leading "/"
* if name is absolute
*/
private String resolveName(String name) {
if (name == null) {
return name;
}
if (!name.startsWith("/")) {//如果不是绝对路径,即相对于classpath根路径
Class c = this;
while (c.isArray()) {
c = c.getComponentType();
}
String baseName = c.getName();//取当前类路径lpp.demo.ResourceUtils
int index = baseName.lastIndexOf('.');//lpp.demo
if (index != -1) {
name = baseName.substring(0, index).replace('.', '/')
+"/"+name;//路径:lpp/demo/pluginxs.xml
}
} else {
name = name.substring(1);//路径:pluginxs.xml
}
return name;
}
}