你所在的位置: 首页 > 正文

读取ClassPath下resource文件的正确姿势

2019-08-24 点击:1308

前锋JAVA发展学院我想昨天分享

image.php?url=0Mr1srpnql

前言

为什么要写这篇文章?作为Java程序员,每次需要读取ClassPath下的资源文件时,您是否曾经去过百度,然后看到以下答案:

CopyThread.currentThread.getContextClassLoader.getResource(ss.properties).getPath;

或者:

CopyObject.class.getResourceAsStream(ss.properties);

您复制并粘贴它并将其放入您自己的项目中,它确实运行。但是当你将jar包作为对其他项目的依赖,或者当Tomcat加载war包时,你还能确保读取你的资源资源文件吗?答案是不。

你是如何解决这个问题的?你如何编写一个不必担心任何环境的代码?中央委员会,请听我说。

2.查看类加载机制

当您看到此标题时,您可能会有一些惊喜,而不是读取ClassPath下的文件?你为什么要谈论类加载机制?

我想知道你是否考虑过ClassPath下资源文件标准中存储的内容?顾名思义,它是一个.class类文件。为什么我们的类正确加载到Java虚拟机(JVM)中,并且我们添加的资源文件不加载?归根结底,你不了解类加载机制,你不能这样做。

类加载机制和类加载器

程序员将源代码写入.Java文件并编译它(javac)以生成.class二进制文件。虚拟机将描述类的数据从类文件加载到内存中,并对数据执行验证,转换解析和初始化,最后形成可由虚拟机直接使用的Java类型。这是虚拟机的类加载机制。

在从宏观角度理解类加载机制之后,下一步是讨论类加载器以及类加载器的工作方式。

顾名思义,类加载器是加载类的设备。 JVM只有两个不同的类加载器:Bootstrap ClassLoader,它是用C ++实现的,是虚拟机本身的一部分。另一个是所有其他类加载器,在JAVA中实现,独立于JVM,并且都继承自抽象类java.lang.ClassLoader。包括扩展类加载器,应用程序类加载器。

当我们编写代码时,我们总是有很多新对象。我们可以创建对象的原因是因为JVM将对象的相应类作为Class类的对象实例加载。这句话有点缠绕,我用代码显示它:

CopyObj obj=new Obj; //Obj对象实例Class o=obj.getClass; //Obj类是Class类的对象实例

通常,在JVM中,由于类加载机制的父代委托模型,我们类的类实例是唯一的。

如果类加载器收到类加载请求,它将不会尝试加载类本身,而是将请求委托给父类加载器。这对于类加载器的每个级别都是如此,因此所有加载请求最终应该传递给顶级启动类加载器。只有当父类加载器返回它无法完成加载请求时才会加载子加载器(它在搜索范围内找不到所需的类)。尝试自己加载它。

这门课也是一种资源

言归正传,通过上面的类加载机制的学习,我们可以得出结论,类加载器将类文件加载到JVM中,并且只加载了一个类加载器。相反,类实例可以获取将其加载到JVM中的类加载器。

用以下代码解释我的最后一段:

CopyObj obj=new Obj;

ClassLoader classLoader=obj.getClass.getClassLoader;

根据我的想法,类加载器可以加载此类,因为该类在类加载器的范围内。由于类加载器可以加载此类文件,因此它还可以将所有资源文件加载到类文件的同一目录中。

因此,我们要确保我们可以读取资源文件,只需在与资源文件相同的目录中调用类的Class对象的getClassLoader方法即可获取类加载器。

例如,我们在与Obj.class相同的目录中有一个属性文件,因此读取属性文件的最正确方法是通过Obj.class.getClassLoader.getResourceAsStream方法。

4.一个错误的例子

要确认上述结论,首先要查看Object.class.getResourceAsStream的源代码:

复制//Class.javapublic InputStream getResourceAsStream(String name){

名称=resolveName(名称);

ClassLoader cl=getClassLoader0; if(cl==null){//系统类。

返回ClassLoader.getSystemResourceAsStream(name);

} return cl.getResourceAsStream(name);

}

正如您从Javadoc文档和源代码中看到的那样:

Class.getResourceAsStream代理用于加载类的ClassLoader,并调用classLoader.getResourceAsStream。如果类的ClassLoader为null,则该类是系统类,因此它被委托给ClassLoader.getSystemResourceAsStream。

这也证实了前面解释的原则:资源文件全部由ClassLoader加载,并且该类也是资源文件。

但是,Object.class.getResourceAsStream可能无法搜索指定的资源文件。原因是上面提到的类加载器的搜索范围,所以不建议使用此方法。

5.FileHelper

最后,我们建议使用一个运行Resources资源的框架FileHelper:

复制

Cn.yueshutong

FileHelper

1.0.RELEASE

阅读资源

下的资源

CopyClassPathResource resource=new ClassPathResource;

String html=resource.readString(commons.html,StandardCharsets.UTF_8);

String htm=resource.readString(commons.htm); byte bytes=resource.readByte(commons.html);

InputStream inputStream=resource.read(commons.html);

String resourcePath=resource.getPath; //获取资源根目录

关于如何正确读取ClassPath下的资源文件,我相信你已经掌握了正确的姿势。

收集报告投诉

亚心网 版权所有© www.xatst.com 技术支持:亚心网 | 网站地图