ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Class和ClassLoader加载资源的区别

2021-07-01 23:02:22  阅读:233  来源: 互联网

标签:name ClassLoader getResource classpath null Class 加载


1. 案例

public static void main(String[] args) {
    System.out.println(TestController.class.getResource(""));
    System.out.println(TestController.class.getResource("/"));
    System.out.println();
    System.out.println(TestController.class.getClassLoader().getResource(""));
    System.out.println(TestController.class.getClassLoader().getResource("/"));
    System.out.println(TestController.class.getClassLoader().getResource("com/example/utils/Test.class"));
}

// 结果
1. 调用类的包路径下的资源才可被加载
file:/E:/ws/demo/target/classes/com/example/utils
2. classpath下的资源都可被加载(路径需要写全,每层以/分隔,参考calss的名称处理)
file:/E:/ws/demo/target/classes
file:/E:/ws/demo/target/classes
3. 永远加载不到
null
4. classpath下的文件加载
file:/E:/ws/demo/target/classes/com/example/utils/Test.class

2. 源码

1. Class加载源码

  • 最终也是调用ClassLoader来获取资源
public java.net.URL getResource(String name) {
    name = resolveName(name);
    // 获取加载该Class的ClassLoader,案例中使用的类加载器是AppClassLoader
    ClassLoader cl = getClassLoader0();
    if (cl==null) {
        // 如果加载该Class的ClassLoader为null,则表示这是一个系统class(C++实现)
        return ClassLoader.getSystemResource(name);
    }
    // 调用ClassLoader的getResource方法
    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();
        }
        // 获取当前类的全限定类名称(包名 + 类名)com.example.utils.Test
        String baseName = c.getName();
        int index = baseName.lastIndexOf('.');
        if (index != -1) {
            // 截取包名并将.替换为/,并拼接传入的文件名称(com/example/utils/user.xml)
            name = baseName.substring(0, index).replace('.', '/')
                +"/"+name;
        }
    } else {
        // 以斜杠开头的文件名称,截掉斜杠后直接返回
        name = name.substring(1);
    }
    return name;
}

2. ClassLoader加载源码

public URL getResource(String name) {
    URL url;
    // 判断父类加载器是否为null,递归调用
    if (parent != null) {
        url = parent.getResource(name);
    } else {
        // 直到系统类加载器Bootstrap
        url = getBootstrapResource(name);
    }
    // 父类加载器都未能加载该资源,由自身类加载器加载
    if (url == null) {
        url = findResource(name);
    }
    return url;
}

3. 区别

  • Class.getResource()只是对传入的文件名称做处理,最终都是通过ClassLoader加载

  • 通过双亲委派机制,逐级向上委托加载,父类加载器都未能加载时,交由当前类加载器进行加载

  • 对于ClassLoader.getResource("/"),’/'表示BootstrapClassLoader的加载范围,因为这个类加载器是C++实现的,所以为null

3. ClassPath详解

1. 在编译打包后的项目中,根目录是`META-INF`和`WEB-INF` 。这个时候,我们在WEB-INF目录下可以看到classes这个文件夹,它就是我们要找的classpath。

2. `classpath:spring-mvc.xml` 中,classpath就是指`WEB-INF/classes/`这个目录的路径。需要声明的一点是,使用`classpath:`这种前缀,只能代表一个文件。

3. `classpath*:**/mapper/*Mapper.xml`,使用`classpath*:`这种前缀,则可以代表多个匹配的文件;`**/mapper/mapping/*Mapper.xml`,双星号`**`表示在任意目录下,也就是说在`WEB-INF/classes/`下任意层的目录,只要符合后面的文件路径,都会被作为资源文件找到。

标签:name,ClassLoader,getResource,classpath,null,Class,加载
来源: https://blog.csdn.net/InterceptWall/article/details/118399903

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有