针对classloader.getresources()介绍和classloader.getresource方法详解这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展SpringMVC(7):
针对classloader.getresources() 介绍和classloader.getresource方法详解这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展<转载>SpringMVC(7): 对Class.getResourceAsStream和ClassLoader.getResourceAsStream方法所使用的资源路径的解释、Class.getResource 和 ClassLoader.getResource、Class.getResource() 和 ClassLoader.getResource() 有什么区别?、Class.getResource()和ClassLoader.getResource()异同及用法等相关知识,希望可以帮助到你。
本文目录一览:- classloader.getresources() 介绍(classloader.getresource方法详解)
- <转载>SpringMVC(7): 对Class.getResourceAsStream和ClassLoader.getResourceAsStream方法所使用的资源路径的解释
- Class.getResource 和 ClassLoader.getResource
- Class.getResource() 和 ClassLoader.getResource() 有什么区别?
- Class.getResource()和ClassLoader.getResource()异同及用法
classloader.getresources() 介绍(classloader.getresource方法详解)
转载自: https://www.cnblogs.com/bhlsheji/p/4095699.html
◆普通情况下,我们都使用相对路径来获取资源,这种灵活性比較大.
比方当前类为com/bbebfe/Test.class
而图像资源比方sample.gif应该放置在com/bbebfe/sample.gif
而假设这些图像资源放置在icons文件夹下,则应该是com/bbebfe/icons/sample.gif
通过当前类文件的路径获取资源主要有例如以下几种方式:
· 如果当前类为com.bbebfe.Test
· 包所在的目录为bin
String imageName = "icons/sample.gif"
1, 通过Class.getResource()定位类路径下的资源(bin/com/bbebfe/icons/sample.gif)
Class clazz = this.getClass();
URL url = clazz.getResource(imageName);
2,通过ClassLoader.getResource()定位包的根文件夹下的资源(bin/icons/sample.gif)
Class clazz = this.getClass();
URLClassLoader loader = (URLClassLoader)clazz.getClassLoader();
URL url = loader.getResource(imageName);
3, 通过ClassLoader.findResource()提供自己定制的方式定位资源
URL url = loader.findResource(imageName);
◆那么这三种方法有那些差别, 我们应该在何时使用哪种方法呢?
· Class.getResource() 方法
该方法实际通过该Class的Class Loader的getResource()方法来获得资源, 在调用ClassLoader的getResource()方法之前, Class.getResource()方法会对资源名称做一定的处理,构建一个该资源的绝对名称(absolute name, 大意是:
+假设资源名称以''/''(''"u002f'') 開始, 则资源的绝对名称是''/''以后的部分.
假设imageName是"/icons/sample.gif", 则在这里会变成"icons/sample.gif"
+否则对于其它情况, 绝对名称将是例如以下形式(给资源名称的前面加上modified_package_name/):
modified_package_name/resource_name (修正的包名称/资源名称)
当中修正的包名称含义是将当前对象所在的包名称中的''.''(''"u002e'')替换为''/''
假设ClassLoader.getResource()方法返回一个值为null的URL, 则Class.getResource()方法终于会将资源请求交给ClassLoader.getSystemResource(java.lang.String).
· ClassLoader.getResource() 方法
该对资源进行查找, 资源的名称是以''/''分隔的路径, 这种方法首先查找自己的父亲ClassLoader,由自己的父ClassLoader来查找资源(实际上, 假设父亲的父亲不是空, 则父亲仍会向上提交查找请求). 假设自己的父ClassLoader是null, 则查找Java虚拟机中内建的class loader, 并将资源请求提交给它们, 假设这些操作都失败了, 则ClassLoader会调用自己的findResource()方法来查找资源.
· ClassLoader.findResource() 方法
该方法在内部查找指定的资源, 假设你实现了自己的Class Loader,则应该重载这种方法以自己特定的方式来查找类文件和资源.
◆通过以上的总结, 我们能够看到三点.
1, 不管是getResource(), 还是findResource(), 这些方法都仅仅是资源的定位方法, 终于都仅仅是返回一个URL, 仅仅是对资源的定位而已, 我们随后应通过自己的方法来读取这些资源. 而在Class和ClassLoader中还定义的有getResourceAsStream方法, 该方法是getResource的增强版, 这里就不介绍了.
2,假设须要以类为相对路径查找资源, 则应该调用Class.getResource()方法, 不要直接调用ClassLoader.getResource()方法. 另外, 除非是你自定义了ClassLoader并重载了findResource方法,否则也不要直接调用ClassLoader.findResource方法, 由于在Class.getResource()方法中会对资源名称作一定的处理, 这在上面介绍了, 以下举个实例:
如果我的当前类在EclipseprojectDatabase下, 类所在的包是com.bbebfe.test, 而icons文件夹放在bin/com/bbebfe/test/文件夹下, 我须要得到icons/sample.gif文件的URL, 则调用this.getClass().getResource()得到的URL是:
file:/E:/MyLife/MyProjects/Eclipse3.2/Database/bin/com/bbebfe/test/icons/disremove.gif
3, 有时候我们希望某个jar库的图像资源在同一个icons下统一管理, 而不是为每一个包以下的Class建一个icons, 也就是说须要以库为相对路径来查找资源, 此时则应该调用ClassLoader.getResource()方法, 举个样例:
·某个project有例如以下的包结构:
com.bbebfe.ui
com.bbebfe.test
com.bbebfe.database
·假设以类为相对路径, 则在每一个包下都必须建立一个icons文件夹, 并放置对应的资源文件. 例如以下:
com.bbebfe.ui/icons/...
com.bbebfe.test/icons/...
com.bbebfe.database/icons/...
·而我们可能希望在根文件夹下放置一个icons文件夹, 把全部资源放置在这里管理, 这样还能够防止资源的反复. 就是例如以下形式
com.bbebfe.ui
com.bbebfe.test
com.bbebfe.database
icons/sample.gif ...
则此时我们应该调用ClassLoader.getResource方法, 因为它没有对资源名称作处理, 也就是说没有将修正的包名加入到资源名称前, 所以它会在类所在的包的根下去查找资源.(执行java程序的语法是java com.bbebfe.ui.Test, 所以根文件夹是com文件夹的上级文件夹).
◆最后, 在Java中对资源进行定位的方法有非常多种, 在Eclipse源码中还有例如以下一段定位文件资源的代码, 还没有时间研究, 以后再谈:
ProtectionDomain domain = Main.class.getProtectionDomain();
CodeSource source = null;
URL result = null;
if (domain != null)
source = domain.getCodeSource();//获得code source
if (source != null)
result = source.getLocation();//获得URL
String path = decode(result.getFile());//
// normalize to not have leading / so we can check the form
File file = new File(path);
path = file.toString().replace(''""'', ''/'');
// create a file URL (via File) to normalize the form (e.g., put
// the leading / on if necessary)
path = new File(path).toURL().getFile();
刚才试了一下,发现假设类路径上有反复的资源,getResource()方法会返回类路径上碰到的第一个资源。
而getResources()则会返回当前类载入器路径上的全部反复资源以及父类载入器上的全部反复资源。
比方,在tomcat/lib文件夹下放置一个zip文件,包括config/aaa.txt文件,
在WEB-INF/lib文件夹下复制一份这个zip文件,
再在src文件夹下放上config/aaa.txt文件,
getResource("config/aaa.txt")返回结果是:
file:/D:/eclipse/workspace/demo/WebContent/WEB-INF/classes/config/aaa.txt
getResources("config/aaa.txt")返回结果是:
file:/D:/eclipse/workspace/demo/WebContent/WEB-INF/classes/config/aaa.txt
jar:file:/D:/apache-tomcat-6.0.16/lib/aaaaa.jar!/config/aaa.txt
jar:file:/D:/eclipse/workspace/demo/WebContent/WEB-INF/lib/bbbbb.jar!/config/aaa.txt
<转载>SpringMVC(7): 对Class.getResourceAsStream和ClassLoader.getResourceAsStream方法所使用的资源路径的解释
18/1/9
一、Class.getResourceAsStream和ClassLoader.getResourceAsStream方法
Class.getResourceAsStream() 会指定要加载的资源路径与当前类所在包的路径一致。
例如你写了一个MyTest类在包com.test.mycode 下,那么MyTest.class.getResourceAsStream("name") 会在com.test.mycode包下查找相应的资源。
如果这个name是以 ''/'' 开头的,那么就会从classpath的根路径下开始查找。
ClassLoader.getResourceAsStream() 无论要查找的资源前面是否带''/'' 都会从classpath的根路径下查找。
所以: MyTest.getClassLoader().getResourceAsStream("name") 和
MyTest.getClassLoader().getResourceAsStream("name") 的效果是一样的。
顺便提下JAVA中类的加载器:
一共有三种加载器
bootstrap classloader :负责加载JAVA核心类( jre 下lib和class目录中的内容)
extension classloader :负责加载JAVA扩展类(jre 下lib/ext 目录中的内容)
system classloader :负责加载应用指定的类 (环境变量classpath中配置的内容)
一个类的加载顺序也是按上面的排列来的,这样就能保证系统的类能先加载。
与此同时用户也可以自己定义ClassLoader,用来加载特殊的资源。
这里就涉及到 Class.getClassLoader() 和 Thread.currentThread.getContextClassLoader()的区别。
举一个简单的例子:
假如某天JAVA给我们提供了一个叫 StartCamera 的类用来启动电脑的标准摄像头,并将这个类打包在一个jar中。
正常情况下,我们要启动摄像头时只需将这个jar配置到classpath中。系统启动时system classloader会将这个类加载到应用中。
但因为摄像头的生产厂家不一样,针对新的设备会有多个不同的StartCamera实现,在应用中我们不知道实际的用户会用到哪种。于是我们就自定义了一个ClassLoader,用来针对具体的设备类型加载相应的StartCamera类。
这样一来就出现:优先加载我们定义的类,加载不到的情况下再加载系统的。 这样的需求,是系统默认的父委托加载机制无法满足的。
Thread.currentThread.getContextClassLoader() 就是这样产生的。 我们使用Thread.currentThread.setContextClassLoader() 可以为当前线程指定相应的ClassLoader,然后用get的方式来获取。
那么上面的加载代码就可能是这样子的:
public void useCamera(){
StartCamera s = this.findClassLoader().loadClass("StartCamera");
s.start();
}
private ClassLoader findClassLoader(){
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if(loader==null){
loader = ClassLoader.getSystemClassLoader();
}
return loader;
}
----------------------------------------------------------------------------------------------
二、Java中getResourceAsStream的用法
1. Class.getResourceAsStream(String path) : path 不以’/''开头时默认是从此类所在的包下取资源,以’/''开头则是从ClassPath根下获取。其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。
2. Class.getClassLoader.getResourceAsStream(String path) :默认则是从ClassPath根下获取,path不能以’/''开头,最终是由ClassLoader获取资源。
3. ServletContext. getResourceAsStream(String path):默认从WebAPP根目录下取资源,Tomcat下path是否以’/''开头无所谓,当然这和具体的容器实现有关。
4. Jsp下的application内置对象就是上面的ServletContext的一种实现。
其次,getResourceAsStream 用法大致有以下几种:
第一: 要加载的文件和.class文件在同一目录下,例如:com.x.y 下有类me.class ,同时有资源文件myfile.xml
那么,应该有如下代码:
me.class.getResourceAsStream("myfile.xml");
第二:在me.class目录的子目录下,例如:com.x.y 下有类me.class ,同时在 com.x.y.file 目录下有资源文件myfile.xml
那么,应该有如下代码:
me.class.getResourceAsStream("file/myfile.xml");
第三:不在me.class目录下,也不在子目录下,例如:com.x.y 下有类me.class ,同时在 com.x.file 目录下有资源文件myfile.xml
那么,应该有如下代码:
me.class.getResourceAsStream("/com/x/file/myfile.xml");
总结一下,可能只是两种写法
第一:前面有 “ / ”
“ / ”代表了工程的根目录,例如工程名叫做myproject,“ / ”代表了myproject
me.class.getResourceAsStream("/com/x/file/myfile.xml");
第二:前面没有 “ / ”
代表当前类的目录
me.class.getResourceAsStream("myfile.xml");
me.class.getResourceAsStream("file/myfile.xml");
最后,自己的理解:
getResourceAsStream读取的文件路径只局限与工程的源文件夹中,包括在工程src根目录下,以及类包里面任何位置,但是如果配置文件路径是在除了源文件夹之外的其他文件夹中时,该方法是用不了的。
Class.getResource 和 ClassLoader.getResource
Class.getResource(String path)
- path以/开头: 从ClassPath根下获取
- path不以/开头: 默认是从此类所在的包下取资源
ClassLoader.getResource(String path)
ClassLoader.getResource的path中不能以/开头,path是默认是从根目录下进行读取的
读取jar里面的文件,我们只能用流去读取,不能用File
Class.getResource() 和 ClassLoader.getResource() 有什么区别?
Class.getResource()
我想知道和之间有什么区别ClassLoader.getResource()
?
编辑:我特别想知道文件/目录级别是否涉及任何缓存。 如“目录列表是否缓存在 Class 版本中?”
AFAIK 以下内容基本上应该做同样的事情,但它们不是:
getClass().getResource() getClass().getClassLoader().getResource()
我在摆弄一些报告生成代码时发现了这一点,该代码WEB-INF/classes/
从该目录中的现有文件中创建了一个新文件。使用 Class
中的方法时,我可以使用
找到部署时存在的文件getClass().getResource()
,但是在尝试获取新创建的文件时,我收到了一个空对象。浏览目录清楚地表明新文件在那里。文件名前面带有正斜杠,如“/myFile.txt”。
另一方面,该ClassLoader
版本确实找到了生成的文件。getResource()
从这个经验来看,似乎对目录列表进行了某种缓存。我是对的,如果是这样,这在哪里记录?
从API
文档开始Class.getResource()
查找具有给定名称的资源。搜索与给定类关联的资源的规则由该类的定义类加载器实现。这个方法委托给这个对象的类加载器。如果此对象由引导类加载器加载,则该方法委托给
ClassLoader.getSystemResource(java.lang.String)。
对我来说,这读作“Class.getResource 真的在调用它自己的类加载器的
getResource()”。这与做getClass().getClassLoader().getResource()
.
但显然不是。有人可以为我提供一些关于这件事的启示吗?
答案1
小编典典回答是否有任何缓存的问题。
我通过运行一个独立的 Java 应用程序进一步研究了这一点,该应用程序使用 getResourceAsStream ClassLoader
方法从磁盘连续加载文件。我能够编辑该文件,并且更改立即反映,即该文件是从磁盘重新加载而没有缓存。
但是: 我正在开发一个包含多个相互依赖的 Maven 模块和 Web 项目的项目。我使用 IntelliJ 作为我的 IDE 来编译和运行 Web
项目。
我注意到上述似乎不再适用,原因是我正在加载的文件现在被烘焙到一个 jar 中并部署到依赖的 web
项目中。我只是在尝试更改目标文件夹中的文件后才注意到这一点,但无济于事。这使得它看起来好像正在进行缓存。
Class.getResource()和ClassLoader.getResource()异同及用法
this.class.getClassLoader()解析
java是面向对象语言,面向对象的语言的宗旨就是万事万物皆对象,那么类、类里面的属性和方法都是对象。java里面的所有的类都是Class类的对象,this.class是获得这个类相对于Class类的对象。
getClassLoader()是获得这个类对象的加载器。只有Class类才有getClassLoader()方法;java设计Class这个类,用于虚拟机对类的管理。当一个类被虚拟机装载完毕的时候,就会创建一个Class类的实例,对于类A就是A.class,对于类B就是B.class。 Class类也提供了许多方法来获取类的信息。要知道,类的装载器分为 "启动类装载器 "、"用户定义装载器 "。它不止一种,Class类需要保存这些信息,getClassLoader()是用来获取这个信息的;
我们来看下面这个例子:
- URL fileURL = CollectionUtil.class.getClassLoader().getResource(fileName);
这个类和这个方法没有直接的关系,只是当后面的fileName是一个相对路径的时候,就会在这个CollectionUtil类的当前位置开始查找资源文件;如果是个绝对路径的话,那前面的类是任意的Java类都可以了,因为.class.getClassLoader()是为了获得一个类加载器,用来加载classpath下的.class文件而已。getResource返回的是一个URL对象,不要简单的认为是这个资源的绝对地址,这是一个Java中封装的对象。
另外,提醒一下,很少是单独用上面这个URL对象的,一般是通过这个URL对象来构造Java中的FIle对象以及Icon对象等等,参考代码如下:
- File file3 = new File(Test.class.getClassLoader().getResource("javaapplication/file3.txt").getFile());
- String icon = "../image/1.gif ";
- button.setIcon(new ImageIcon(getClass() .getResource(icon)));
Class.getResource和ClassLoader.getResource解析
Java中取资源时,经常用到Class.getResource和ClassLoader.getResource,这里来看看他们在取资源文件时候的路径问题。
Class.getResource()
- Class.getResouece(String path);
path不以“/”开头时,默认是从此类所在的包下取资源;path以“/”开头时,则是从ClassPath根下获取;
文件结构如下:
如果我们想在Test.java中分别取1~3.xml文件,该怎么实现?
- package testpackage;
- public class TestMain {
- public static void main(String[] args) {
- // 当前类(class)所在的包目录
- System.out.println(TestMain.class.getResource(""));
- // class path根目录
- System.out.println(TestMain.class.getResource("/"));
- // TestMain.class在<bin>/testpackage包中
- // 1.properties 在bin目录(class根目录)
- System.out.println(TestMain.class.getResource("/1.properties"));
- // TestMain.class在<bin>/testpackage包中
- // 2.properties 在<bin>/testpackage包中
- System.out.println(TestMain.class.getResource("2.properties"));
- // TestMain.class在<bin>/testpackage包中
- // 3.properties 在<bin>/testpackage.subpackage包中
- System.out.println(TestMain.class.getResource("subpackage/3.properties"));
- }
- }
Class.getResource()和Class.getResourceAsStream()使用时,在路径选择上是一样的。
Class.getClassLoader().getResource(String path)
当前以getClassLoader().getResource(String path) ,path不能以“/”开头时,是从ClassPath根下获取;
- package testpackage;
- public class TestMain {
- public static void main(String[] args) {
- TestMain t = new TestMain();
- System.out.println(t.getClass());
- System.out.println(t.getClass().getClassLoader());
- System.out.println(t.getClass().getClassLoader().getResource(""));
- System.out.println(t.getClass().getClassLoader().getResource("/"));//获取值为null
- }
- }
运行结果:
- class testpackage.TestMain
- sun.misc.Launcher$AppClassLoader@1fb8ee3
- file:/E:/workspace/Test/bin/
- null
还是上面的文件结构,使用Class.getClassLoader().getResourse(String path)该怎么实现呢?
- package testpackage;
- public class Test {
- public static void main(String[] args) {
- TestMain t = new TestMain();
- System.out.println(t.getClass().getClassLoader().getResource(""));
- System.out.println(t.getClass().getClassLoader().getResource("1.properties"));
- System.out.println(t.getClass().getClassLoader().getResource("testpackage/2.properties"));
- System.out.println(t.getClass().getClassLoader().getResource("testpackage/subpackage/3.properties"));
- }
- }
Class.getClassLoader().getResource()和Class.getClassLoader().getResourceStream()使用时,在路径选择上也是一样的。
今天的关于classloader.getresources() 介绍和classloader.getresource方法详解的分享已经结束,谢谢您的关注,如果想了解更多关于<转载>SpringMVC(7): 对Class.getResourceAsStream和ClassLoader.getResourceAsStream方法所使用的资源路径的解释、Class.getResource 和 ClassLoader.getResource、Class.getResource() 和 ClassLoader.getResource() 有什么区别?、Class.getResource()和ClassLoader.getResource()异同及用法的相关知识,请在本站进行查询。
本文标签: