ClassLoader加载项目下的资源文件

Bootstrap、ExtClassLoader、AppClassLoader

首先先要知道三种类加载器的作用。
启动类加载器(Bootstrap
启动类加载器是C++实现的,负责将<JAVA_HOME>/lib路径下的核心类库或-Xbootclasspath参数指定的路径下的jar包加载到内存中,出于安全考虑,Bootstrap只加载包名为java、javax、sun等开头的类

扩展类加载器(ExtClassLoader
ExtClassLoaderJava实现的,是sun.misc.Launcher的静态内部类,负责加载<JAVA_HOME>/lib/ext目录下或者由系统变量-Djava.ext.dir指定路径中的类库

系统类加载器(AppClassLoader
AppClassLoader也是Java实现的,同样也是sun.misc.Launcher的静态内部类,负责加载系统类路径java -classpath-D java.class.path指定路径下的类库。我们口中常说的classpath就是AppClassLoader负责加载的。通过ClassLoader#getSystemClassLoader()方法可以获取到该类加载器

ClassLoader加载资源

我们启动服务时,IDE会输出当前的Java环境和-classpath-classpath指定了所有JVM要加载的文件和路径,里面一定包含了你当前项目编译后的路径target/classes路径。
在这里插入图片描述
单元测试的-classpath先指定了target/test-classes,然后是target/classes
在这里插入图片描述
这就意味着,使用ClassLoader在单元测试获取资源和正常服务获取资源有差别。

下面是用web服务做的测试

classpath

-classpath只有target/classes路径,加载资源配置文件时,如果不写资源名,只写./、""、/

  • src下的main函数中使用ClassLoaderClassPathResource获取资源文件
    使用ClassLoader#getResource(String name)

    • name=./返回target/classpath/
    • name=""返回在target/classpath/
    • name=/返回null

    使用new ClassPathResource(String path)
    path=/、./、"",都表示target/classes/,对于path=/Spring做了处理

  • 启动的服务,使用ClassLoaderClassPathResource获取资源文件
    对于/、./、""ClassLoaderClassPathResource都表示target/classes/

test-classpath

-classpath先是target/test-classes,然后是target/classes,加载资源配置文件时,如果不写资源名,只写./、""、/

  • 单元测试的main函数中使用ClassLoaderClassPathResource获取资源文件
  • 单元测试方法中调用服务,服务中使用ClassLoaderClassPathResource获取资源文件
  • 单元测试方法中使用ClassLoaderClassPathResource获取资源文件

以上三种,都是优先从target/test-classes加载相应的资源文件,如果没有,再去target/classes下加载资源。
使用ClassLoader时,./和""返回target/test-classes/返回null
使用ClassPathResource时,/、./和""都返回target/test-classes

ClassLoader#getResource(String name)和Class#getResource(String name)的异同

  • ClassLoader#getResource(String name)
    ClassLoader使用双亲委派模型去查找文件资源,先Bootstrap,再ExtClassLoader,最后AppClassLoader,返回的是target/classes或者target/test-classes
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;
}
  • Class#getResource(String name)
    源码中先将文件路径定位到当前文件所在的路径下,然后优先获取用户使用的Class中的ClassLoader,如果为null(一般情况下都是AppClassLoader),调用ClassLoader.getSystemResource(name);方法,这个方法中调用了ClassLoader#getSystemClassLoader(),此方法通常返回的是AppClassLoader
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);
}

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;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值