Web基础之Class与ClassLoader的getResource区别

前言

在Web开发中经常要加载项目下的各种资源,有一种方法是用ClassLoader或者Class类提供的getResource来加载。本文将从代码上来分析两者的区别

正文

经常看到下面类似的代码,往往很容易搞混

public static void loadSourceWithClassLoader() {
        SysFilePath.class.getResource("/org/easyutil/resources/utf8.txt"); //从classpath下加载资源
        SysFilePath.class.getResource("utf8.txt");//从当前目录下加载资源
        SysFilePath.class.getClassLoader().getResource("org/easyutil/resources/utf8.txt");//从classpath下加载资源
    }

important note:这里需要记住一点的就是class.getResource使用ClassLoader类中的getResource实现的。也就是说两者的本质都是使用加载器来加载资源

加载器种类很多,在java项目有下面三种加载器
1)Bootstrap ClassLoader
2)Extension ClassLoader
3)App ClassLoader
如果是Web的项目且使用的是Tomcat容器,那么加载器还包括
4)WebAppClassLoader
不同的加载器都有一个指定的加载目录,自己理解为是classpath.所以ClassLoader.getResource(path)从classpath中加载path路径下的资源,这里path是开头不能是“/”且其后按照/分割的格式

从上面的可以知道了
SysFilePath.class.getClassLoader().getResource("org/easyutil/resources/utf8.txt");
加载的就是classpath路径下的资源,具体实现代码如下

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

从加载器继承体系的最上层查找资源,如果找不到资源在一层层下来直到使用当前加载器(默认加载目录)加载资源(findResource)

再看看Class类中的getResource怎么加载资源的.其实开头是否要加“/”是业务要求导致的(这个类的功能需求决定的),而本质是使用ClassLoader来加载资源,它要求路径开头不需要“/”.这么说来开头是否要“/”会产生不同的代码逻辑处理,我们看看这些不同逻辑是怎么处理的

Class类的getResource

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

最后获取当前的ClassLoader加载资源,那么这里的name是什么样子呢?

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

如果开头不是“/”则获取当前类的包路径,“.”转成以“/”分割的路径然后连接上name(外面指定的资源路径),这样直接定位到classpath下当前所在的路径下的指定name的路径中的资源
如果以“/”开头则,直接去掉“/”,表示定位到classpath下的name路径所在的资源

最后总结得出下面结论
class.getResource有下面两个算法

  1. 如果以“/”开头则加载classpath下的资源
  2. 如果不以“/”开头则加载当前目录下的资源

    ClassLoader.getResource算法

  3. 从classpath加载资源,且开头不能是“/”其后按照“/”分割的路径(相对路径)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值