obj.getClass().getResourceAsStream() 和 obj.getClass().getClassLoader().getResourceAsStream() 资源路径差别

在学习过程中,将部分配置信息放在 properties 文件中,代码中读取时碰到 obj.getClass().getResourceAsStream() 无法加载资源,而 obj.getClass().getClassLoader().getResourceAsStream() 可以正常加载资源。

作为初学者,对于其中的区别还没有反应过来,先使用后者把代码跑起来。后来查了资料后,对两者的差别才有些基本了解。

这里记录两者的差别和各自使用注意点:

  1. obj.getClass().getResourceAsStream():如果资源路径不是以 / 开头,则根据当前类的包路径作为相对路径进行资源加载;如果资源路径以 / 开头,则从 classpath 加载资源;使用时注意资源和当前类的相对路径。
  2. obj.getClass().getClassLoader().getResourceAsStream():只从 classpath 加载资源。

查到资料后就准备查看代码逻辑是怎么实现的,这里把 obj.getClass().getResourceAsStream() 的代码中对资源路径的处理方法摘录下来。

进入方法先对路径进行处理:

public InputStream getResourceAsStream(String name) {
    name = resolveName(name);

    Module thisModule = getModule();
    if (thisModule.isNamed()) {
        // check if resource can be located by caller
        if (Resources.canEncapsulate(name)
            && !isOpenToCaller(name, Reflection.getCallerClass())) {
            return null;
        }

        // resource not encapsulated or in package open to caller
        String mn = thisModule.getName();
        ClassLoader cl = classLoader;
        try {

            // special-case built-in class loaders to avoid the
            // need for a URL connection
            if (cl == null) {
                return BootLoader.findResourceAsStream(mn, name);
            } else if (cl instanceof BuiltinClassLoader) {
                return ((BuiltinClassLoader) cl).findResourceAsStream(mn, name);
            } else {
                URL url = cl.findResource(mn, name);
                return (url != null) ? url.openStream() : null;
            }

        } catch (IOException | SecurityException e) {
            return null;
        }
    }

    // unnamed module
    ClassLoader cl = classLoader;
    if (cl == null) {
        return ClassLoader.getSystemResourceAsStream(name);
    } else {
        return cl.getResourceAsStream(name);
    }
}

处理代码如下:

/**
 * Add a package name prefix if the name is not absolute. Remove leading "/"
 * if name is absolute
 */
private String resolveName(String name) {
    if (!name.startsWith("/")) {
        String baseName = getPackageName();
        if (!baseName.isEmpty()) {
            int len = baseName.length() + 1 + name.length();
            StringBuilder sb = new StringBuilder(len);
            name = sb.append(baseName.replace('.', '/'))
                .append('/')
                .append(name)
                .toString();
        }
    } else {
        name = name.substring(1);
    }
    return name;
}

从代码中可以看出,obj.getClass().getResourceAsStream() 对路径的处理,和相对路径的拼接。

问题是小问题,通过在 jdk 的代码中翻出了实现逻辑,加深了理解,但是知道的越多,不知道的就越多,类加载器、模块(Module)诸多概念等学习到了再看。

到此,本篇记录结束。

posted @ 2025-03-13 10:25  螺旋质子  阅读(12)  评论(0)    收藏  举报