Class和ClassLoader加载资源的区别
2021/7/1 23:22:39
本文主要是介绍Class和ClassLoader加载资源的区别,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
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/`下任意层的目录,只要符合后面的文件路径,都会被作为资源文件找到。
这篇关于Class和ClassLoader加载资源的区别的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-05Easysearch 可搜索快照功能,看这篇就够了
- 2025-01-04BOT+EPC模式在基础设施项目中的应用与优势
- 2025-01-03用LangChain构建会检索和搜索的智能聊天机器人指南
- 2025-01-03图像文字理解,OCR、大模型还是多模态模型?PalliGema2在QLoRA技术上的微调与应用
- 2025-01-03混合搜索:用LanceDB实现语义和关键词结合的搜索技术(应用于实际项目)
- 2025-01-03停止思考数据管道,开始构建数据平台:介绍Analytics Engineering Framework
- 2025-01-03如果 Azure-Samples/aks-store-demo 使用了 Score 会怎样?
- 2025-01-03Apache Flink概述:实时数据处理的利器
- 2025-01-01使用 SVN合并操作时,怎么解决冲突的情况?-icode9专业技术文章分享
- 2025-01-01告别Anaconda?试试这些替代品吧