Class.getResource 和 ClassLoader.getResource获取资源文件

关于获取资源文件,Class.getResource 和 ClassLoader.getResource 的区别
彻底搞懂Class.getResource和ClassLoader.getResource的区别和底层原理

1. ClassLoader.getResource

有两种方法获取当前的ClassLoader

ClassLoader classLoader = this.getClass().getClassLoader();
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

我们可以使用获取到的ClassLoadergetResource(String name)方法来获取想要的资源文件的URL,其中要注意:
在使用 ClassLoader().getResource 获取路径时,不能以 "/" 开头,且路径总是从 classpath 根路径开始

使用如下:
在这里插入图片描述

public class GetResourceTest {
    public void getResourceByClassLoader(){
        //sun.misc.Launcher$AppClassLoader@18b4aac2
        ClassLoader classLoader = this.getClass().getClassLoader();
        
        //file:/D:/ideaProject/simplespring/target/classes/
        System.out.println(classLoader.getResource(""));

        //file:/D:/ideaProject/simplespring/target/classes/com/resourceloadpag/testpag/GetResourceTest.class
        System.out.println(classLoader.getResource("com/resourceloadpag/testpag/GetResourceTest.class"));

        sun.misc.Launcher$AppClassLoader@18b4aac2
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        
        //null
        System.out.println(contextClassLoader.getResource("/"));

        //file:/D:/ideaProject/simplespring/target/classes/test
        System.out.println(contextClassLoader.getResource("test"));

        //在获取文件时,我们还可以通过 getResourceAsStream 直接获取文件输入流
        InputStream inputStream = contextClassLoader.getResourceAsStream("test");
    }

    public static void main(String[] args) {
        GetResourceTest getResourceTest = new GetResourceTest();
        getResourceTest.getResourceByClassLoader();
    }
}

2. Class.getResource

对于这个方法,getResource("") 获取的是当前类所在包的路径,而 getResource("/") 获取的是 classpath 根路径

public class GetResourceTest {
    public void  getResourceByClass(){
        //file:/D:/ideaProject/simplespring/target/classes/com/resourceloadpag/testpag/
        URL url = this.getClass().getResource("");
        System.out.println(url);

        //file:/D:/ideaProject/simplespring/target/classes/com/resourceloadpag/testpag/GetResourceTest.class
        System.out.println(this.getClass().getResource("GetResourceTest.class"));

        //file:/D:/ideaProject/simplespring/target/classes/
        System.out.println(this.getClass().getResource("/"));

        //file:/D:/ideaProject/simplespring/target/classes/com/resourceloadpag/testpag/GetResourceTest.class
        System.out.println(this.getClass().getResource("/com/resourceloadpag/testpag/GetResourceTest.class"));

        //null
        System.out.println(this.getClass().getResource("test"));

        //file:/D:/ideaProject/simplespring/target/classes/test
        System.out.println(this.getClass().getResource("/test"));
		
		//在获取文件时,我们还可以通过 getResourceAsStream 直接获取文件输入流
        InputStream inputStream = this.getClass().getResourceAsStream("/test");
    }
}

总结一下Class.getResource()ClassLoader().getResource() 的区别

  • Class.getResource() 可以从当前 Class 所在包的路径开始匹配获取资源,也可以从 classpath 根路径开始匹配获取资源;
  • ClassLoader().getResource() 只能从 classpath 根路径开始匹配获取资源;
  • Class.getResource() 从当前包所在路径获取资源时不能以 "/" 开头,而从 classpath 根路径获取资源时必须以 "/" 开头;
  • ClassLoader().getResource() 不能以 "/" 开头,且路径总是从 classpath 根路径开始;
  • 它们都能通过 getResourceAsStream() 方法获取对应路径文件的输入流,文件路径匹配机制和其 getResource() 方法一样;

3. 源码解读

通过源码来比较这两个方法的不同,首先看一下Class.getResource的源码

public java.net.URL getResource(String name) {
    name = resolveName(name);
    ClassLoader cl = getClassLoader0();//获取当前类的类加载器
    if (cl==null) {//如果类加载器为null,那么说明是BootstrapClassLoader,当前类是系统类
        // A system class.
        return ClassLoader.getSystemResource(name);
    }
    return cl.getResource(name);
}

在这里插入图片描述
可以看到当前类的类加载器是AppClassLoader,接下来就是调用当前类加载器的getResource方法;
也就是说,Class.getResourceClassLoader.getResource实际上都是调用ClassLoader 类的getResource方法,只不过在Class.getResource中害有一步resolveName,下面看一下resolveName做了什么

/**
 * 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("/")) { //对于不以/开头的文件
        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可以以"/"开头;

说完了这些,再去看一下ClassLoader.getResource究竟做了什么

public URL getResource(String name) {
    URL url;
    if (parent != null) {//先交给父亲处理(双亲委派机制)
        url = parent.getResource(name);
    } else {//到了BootstrapClassLoader系统启动类加载器
        url = getBootstrapResource(name);
    }
    if (url == null) {//最后如果都没有加载到,双亲委派加载失败,则加载应用本身自己的加载器
        url = findResource(name);
    }
    return url;
}

阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
getResource()方法是Java中用于获取源的方法之一。根据引用所提及的不同方式,可以通过class.getResource()和classloader.getResource()来获取源路径。这两种方式在实现上存在差异。 具体来说,class.getResource()方法是通过类对象来获取源路径的,它是相对于当前类的位置进行查找源。而classloader.getResource()方法则是通过类加载器来获取源路径,它是相对于类加载器的根路径进行查找源。这意味着,使用class.getResource()方法时,源文件必须与类文件在同一个目录下或其子目录下;而使用classloader.getResource()方法时,源文件可以位于任何地方。 这两种方法在底层实现上存在一定的差异。具体的原理可以参考引用中提到的文章,它详细解释了Class.getResource()和ClassLoader.getResource()的区别和底层原理。 总之,通过getResource()方法可以获取到指定源的路径,具体使用哪种方式取决于源文件的位置和使用场景。对于更深入的了解,可以参考引用中的文章,它详细展开了getResource()方法在Tomcat 7和Tomcat 8中的差异和对jdk原生getResource()的解析。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [getResource()获取源的那些事](https://blog.csdn.net/qq_35076190/article/details/115568428)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [Java学习之getResource方法获取项目下文件路径](https://blog.csdn.net/weixin_42586723/article/details/109156311)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天你学习了么

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值