• 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"));
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    双亲委派机制、先给父类加载器中尝试加载、然后再到自己的。

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这个关键在于对 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
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

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

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

  • 相关阅读:
    CData API Server全面且文档完整的API
    进程间的通信方式
    Centos安装telnet
    Natapp内网穿透
    stable diffusion和gpt4-free快速运行
    「React深入」一文吃透虚拟DOM和diff算法
    论文阅读之Learning and Generalization of Motor Skills by Learning from Demonstration
    js 实现继承
    MybatisPlus —注解汇总
    HDLbits exercises 3 (procedures节选题)
  • 原文地址:https://blog.csdn.net/lijinxiong520/article/details/125568971