Class.getResource和ClassLoader.getResource区别与分析

来源:互联网 发布:mean it 编辑:程序博客网 时间:2024/05/22 12:22
零、 前言

在一个获取文件路径的代码内容上发现单元测试出现NullPointer, 但是这段代码却在服务器正常运行了两年多, 借此机会想认真探索下这两个方法的区别。



一、 区别

区别从代码输出结果来看比较清晰,

文件结构图: 



以下为在多个场景下使用方式的代码:

package com.wenniuwuren.test;/** * 获取文件路径 * Created by wenniuwuren on 15/8/14. */public class GetResourceTest {    public static void main(String[] args) {        // 带 “/” 的其实就是返回根目录        System.out.println("GetResourceTest.class.getResource(\"/\") -----> "                + GetResourceTest.class.getResource("/"));        System.out.println("GetResourceTest.class.getResource(\"/DD.DD\") -----> "                + GetResourceTest.class.getResource("/DD.DD"));        // *************************************************        // 返回当前路径        System.out.println("GetResourceTest.class.getResource(\"\") -----> "                + GetResourceTest.class.getResource(""));        System.out.println("GetResourceTest.class.getResource(\"AA.AA\") -----> "                + GetResourceTest.class.getResource("AA.AA"));        System.out.println("GetResourceTest.class.getResource(\"subtest/BB.BB\") -----> "                + GetResourceTest.class.getResource("subtest/BB.BB"));        System.out.println("GetResourceTest.class.getResource(\"../CC.CC\") -----> "                + GetResourceTest.class.getResource("../CC.CC"));        // 查找classloader root。 用 getClassLoader 最容易出问题, 因为是根据类加载器来的, 类加载器多种多样可能在不同环境下产生不同结果        GetResourceTest getResourceTest = new GetResourceTest();        System.out.println("getResourceTest.getClass().getClassLoader().getResource(\"\") -----> "                + getResourceTest.getClass().getClassLoader().getResource(""));        System.out.println("getResourceTest.getClass().getClassLoader().getResource(\"/\") -----> "                + getResourceTest.getClass().getClassLoader().getResource("/"));        /**         * 从输出结果来看总结上述: Class.class.getResource("/")  ==  Class.getClass().getClassLoader().getResource("")         */        // 这是一种可以避免在不同Web容器下获取路径异常的方法        System.out.println("GetResourceTest.class.getProtectionDomain().getCodeSource().getLocation().getPath() -----> "                + GetResourceTest.class.getProtectionDomain().getCodeSource().getLocation().getPath());    }}



二、 从源码角度分析
 
分析前先看个 Java 类加载的架构图, 有助于下文理解:

1. Class.getResource
算法基本为: 搜索策略为此类关联的类加载器实现的, 即这个方法委托给这个对象的类加载器,如果对象是被 Bootstrap 类加载器加载的, 则进入 ClassLoader.getSystemResource() 方法, 这个方法先找系统级别的类加载器(这个加载器是一般应用启动的类加载器), 如果找不到则使用虚拟机内置的类加载器。
如果传的参数是“/”则返回根路径, 传的是具体文件名就返回文件绝对路径。
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);    }



2. ClassLoader.getResource
会先从父加载器去找资源, 如果父加载器为 null 则从虚拟机内置加载器去查找(这步何上面最后一步相同), 如果还没有, 则去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;    }



3 0
原创粉丝点击