getResource和getResourceAsStream文件路径分析

一,简介

       在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;
    }

}

      

      

猜你喜欢

转载自pandan-xyz.iteye.com/blog/2269302