CoderLi

V1

2022/07/01阅读:9主题:姹紫

Java getResource

最近在工作中有用到资源加载、发现 ClassClassLoader 都可以加载 classPath 下的文件

对比一下他们之间的异同

微信公众号:CoderLi
package com.demo.test.get;

public class GetResourceMain {
    public static void main(String[] args) {
      
        Class<GetResourceMain> getResourceMainClass = GetResourceMain.class;
        ClassLoader classLoader = getResourceMainClass.getClassLoader();

        System.out.println("classGetResource:" + getResourceMainClass.getResource(""));
        System.out.println("classLoaderGetResource:" + classLoader.getResource(""));

        System.out.println("/ classGetResource:" + getResourceMainClass.getResource("/"));
        System.out.println("/ classLoaderGetResource:" + classLoader.getResource("/"));

        System.out.println("logback.xml classGetResource:" + getResourceMainClass.getResource("logback.xml"));
        System.out.println("logback.xml classLoaderGetResource:" + classLoader.getResource("logback.xml"));

        System.out.println("/logback.xml classGetResource:" + getResourceMainClass.getResource("/logback.xml"));
        System.out.println("/logback.xml classLoaderGetResource:" + classLoader.getResource("/logback.xml"));

        System.out.println("jar inner file classLoaderGetResource:" + classLoader.getResource("META-INF/maven/org.slf4j/slf4j-api/pom.xml"));

    }
}

classGetResource:file:/Users/xxxx/IdeaProjects/logbackTest/target/classes/com/demo/test/get/ classLoaderGetResource:file:/Users/xxxx/IdeaProjects/logbackTest/target/classes/ / classGetResource:file:/Users/xxxx/IdeaProjects/logbackTest/target/classes/ / classLoaderGetResource:null logback.xml classGetResource:null logback.xml classLoaderGetResource:file:/Users/xxxx/IdeaProjects/logbackTest/target/classes/logback.xml /logback.xml classGetResource:file:/Users/xxxx/IdeaProjects/logbackTest/target/classes/logback.xml /logback.xml classLoaderGetResource:null jar inner file classGetResource:jar:file:/Users/xxxx/.m2/repository/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar!/META-INF/maven/org.slf4j/slf4j-api/pom.xml jar inner file classLoaderGetResource:jar:file:/Users/xxxx/.m2/repository/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar!/META-INF/maven/org.slf4j/slf4j-api/pom.xml

通过日志分析我们得知 Class#getResouce 如果传入的参数以 / 开头的话则获取到的是当前 classpath 的绝对路径。如果不是的话、则是获取到当前 class 所在的路径

ClassLoader#getResource 则默认获取到的就是 classpath 下的路径、如果传入的参数以 / 开头则返回 null

ClassLoader#getResource

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

最终还是调用 ClassLoader

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

这个关键在于对 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;
}

如果是以 / 开头、则直接去掉 / 然后返回

如果不是则获取当前 class 的全路径、然后替换 . 然后返回

分类:

后端

标签:

Java

作者介绍

CoderLi
V1