为什么要写这篇文章?作为一个Java程序员,你有没有过每次需要读取ClassPath下的资源文件都要去百度一下,然后看到下面的回答:
CopyThread.currentThread()。getContextClassLoader()。getResource(ss.properties)。getPath();
或者:
copy object . class . GetResourcesStream(ss . properties);
你复制粘贴,放到自己的项目里运行,它就真的运行了。但是当jar包作为其他项目的依赖项使用时,或者当war包被Tomcat加载时,你还能保证你的资源资源文件被读取吗?答案是否定的。
原因是什么,如何解决?怎样才能写出万无一失的代码而完全不用担心任何环境?为什么,请一起听我说。
2.看看类加载机制
看到这个标题你可能会很惊讶。你不是说要读ClassPath下的文件吗?为什么说类加载机制。
我想知道您是否考虑过在标准类路径下的资源文件中存储了什么。顾名思义,就是一个. class文件。为什么我们的类可以正确加载到Java虚拟机(JVM)中,但是自己添加的资源文件加载失败?归根结底,如果不了解类的加载机制,就不能举一反三。
类加载机制和类加载器
程序员将源代码写入。Java文件,并通过(javac)编译它以生成。类二进制文件。虚拟机将描述类的数据从类文件加载到内存中,并对数据进行验证、转换、解析和初始化,最终形成虚拟机可以直接使用的Java类型,这就是虚拟机的类加载机制。
在对类加载机制有了一个宏观的了解之后,我们再来详细说说类加载器及其工作原理。
类加载器,顾名思义,就是加载类的设备。JVM中只有两种不同的类加载器:Bootstrap ClassLoader,用C++实现,是虚拟机本身的一部分。另一个是所有其他类加载器,它们用JAVA实现,独立于JVM,并且都继承自抽象类java.lang.ClassLoader包括一个扩展类加载器和一个应用程序类加载器。
当我们写代码时,许多对象总是新的。我们之所以能够创建新的对象,是因为这个对象对应的类已经被JVM加载为类类的对象实例。这句话有点绕口。我将用代码展示它:
copy Obj = new Obj();//Obj对象实例Class o = Obj . GetCLaSS();//Obj类是类类的对象实例
在JVM中,一般来说,我们类的类实例是唯一的,这要归功于类加载机制的父委托模型。
如果一个类装入器收到一个类装入请求,它首先不会尝试自己装入类,而是将请求委托给父类装入器来完成,对于每一级的类装入器都是如此。因此,所有加载请求最终都应该传输到顶层启动类加载器。只有当父类加载器反馈它不能完成加载请求时(在其搜索范围内找不到所需的类),子类加载器才会尝试自己加载它。
3.类也是一种资源
离家近一点,通过以上对类加载机制的研究,我们可以得出这样的结论:一个类文件被一个类加载器加载到JVM中,只有一个类加载器会加载它。相反,一个类实例可以得到一个类加载器,这个类加载器将它加载到JVM中。
用代码解释我最后的话如下:
copy Obj = new Obj();
CLaSS loader CLaSS loader = obj . GetCLaSS()。GetClassLoader();
按照我的思路,类加载器可以加载这个类,因为它在类加载器的搜索范围内。因为类加载器可以加载这个类文件,所以它也可以加载这个类文件的同一级别目录下的所有资源文件。
因此,如果我们想保证一个资源文件可以被读取,我们只需要调用与资源文件在同一个目录下的类的class对象的getClassloader()方法就可以得到类加载器。
例如,我们在与Obj.class相同的目录中有一个属性文件,所以我们读取属性文件最正确的方法是通过obj.class.getclassloader()方法。getresourcestream()。
4.错误的例子
要验证以上结论,先看object.class.getresourcestream()的源代码:
copy//class . javapublic InputStream GetResourcesStream(字符串名称){
name = resolveName(名称);
class loader cl = GetClassLoader0();if (cl==null) { // A系统类。
返回ClassLoader . GetSystemResourcesStream(名称);
}返回cl.getResourceAsStream(名称);
}
从Javadoc文档和源代码中可以看出:
类. Class.getResourceAsStream()由加载该类的类加载器实现,并调用类加载器. Class.getResourceAsStream()。如果类的classloader为null,则表示该类是系统类,因此委托给class loader . getsystemresourcestream..
这一点也印证了前面解释的原理:资源文件是由ClassLoader加载的,类也是资源文件。
但是,指定的资源文件可能无法通过object.class.getResourceStream()进行搜索,因为前面提到的类加载器的搜索范围,所以不建议使用此方法。
5.FileHelper
最后,推荐一个用于操作资源资源的框架文件助手:
复制
cn .岳树彤
FileHelper
1.0.RELEASE
阅读资源下的资源
copy class path resource = new class path resource();
string html = resource . ReadString(commons . html,StandardCharsets。UTF _ 8);
string htm = resource . ReadString(commons . htm);byte[]bytes = resource . read byte(commons . html);
InputStream InputStream = resource . read(commons . html);
string resource path = resource . getpath();//获取资源根目录
我相信您已经掌握了如何正确读取CLaSS下的资源文件的正确姿势。
1.《classpath 读取ClassPath下resource文件的正确姿势》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《classpath 读取ClassPath下resource文件的正确姿势》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/tiyu/1075618.html