jdk9新特征系列(二):访问资源

栏目:JDK9 新特性 作者:admin 日期:2017-10-07 评论:0 点击: 138 次

资源是应用程序使用的数据,例如图像,音频,视频,文本文件等。Java提供了一种通过在类路径上定位资源来访问资源的位置无关的方式。 需要与在JAR中打包类文件相同的方式打包资源,并将JAR添加到类路径。 通常,类文件和资源打包在同一个JAR中。 访问资源是每个Java开发人员执行的重要任务。

1. 在JDK 9之前访问资源

在Java代码中,资源由资源名称标识,资源名称是由斜线(/)分隔的一串字符串。 对于存储在JAR中的资源,资源名称仅仅是存储在JAR中的文件的路径。 例如,在JDK 9之前,存储在rt.jar中的java.lang包中的Object.class文件是一个资源,其资源名称是java/lang/Object.class。
在JDK 9之前,可以使用以下两个类中的方法来访问资源:
java.lang.Class
java.lang.ClassLoader
资源由ClassLoader定位。 一个Class代理中的资源寻找方法到它的ClassLoader。 因此,一旦了解ClassLoader使用的资源加载过程,将不会在使用Class类的方法时遇到问题。 在两个类中有两种不同的命名实例方法:
URL getResource(String name)
InputStream getResourceAsStream(String name)
两种方法都会以相同的方式找到资源。 它们的差异仅在于返回类型。 第一个方法返回一个URL,而第二个方法返回一个InputStream。 第二种方法相当于调用第一种方法,然后在返回的URL对象上调用openStream()。
ClassLoader类包含三个额外的查找资源的静态方法:
static URL getSystemResource(String name)
static InputStream getSystemResourceAsStream(String name)
static Enumeration<URL> getSystemResources(String name)
这些方法使用系统类加载器(也称为应用程序类加载器)来查找资源。 第一种方法返回找到的第一个资源的URL。 第二种方法返回找到的第一个资源的InputStream。 第三种方法返回使用指定的资源名称找到的所有资源的URL枚举。
要找到资源,有两种类型的方法可以从——getSystemResource*和getResource*中进行选择。 在讨论哪种方法是最好的之前,重要的是要了解有两种类型的资源:
系统资源
非系统资源
你必须了解他们之间的区别,以了解资源查找机制。系统资源是在bootstrap类路径,扩展目录中的JAR和应用程序类路径中找到的资源。非系统资源可以存储在除路径之外的位置,例如在特定目录,网络上或数据库中。 getSystemResource()方法使用应用程序类加载程序找到一个资源,委托给它的父类,它是扩展类加载器,后者又委托给它的父类(引导类加载器)。如果你的应用程序是独立的应用程序,并且它只使用三个内置的JDK类加载器,那么你将很好的使用名为getSystemResource *的静态方法。它将在类路径中找到所有资源,包括运行时映像中的资源,如rt.jar文件。如果你的应用程序是在浏览器中运行的小程序,或在应用程序服务器和Web服务器中运行的企业应用程序,则应使用名为getResource*的实例方法,它可以使用特定的类加载器来查找资源。如果在Class对象上调用getResource*方法,则会使用当前类加载器(加载Class对象的类加载器)来查找资源。
传递给ClassLoader类中所有方法的资源名称都是绝对的,它们不以斜线(/)开头。 例如,当调用ClassLoader的getSystemResource()方法时,将使用java/lang/Object.class作为资源名称。
Class类中的资源查找方法可以指定绝对和相对资源名称。绝对资源名称以斜线开头,而相对资源名称不用。 当使用绝对名称时,Class类中的方法会删除前导斜线并委派给加载Class对象的类加载器来查找资源。 以下调用
Test.class.getResource("/resources/test.config");
会被转换成
Test.class.getClassLoader().getResource("resources/test.config");
当使用相对名称时,Class类中的方法预先添加了包名称,在使用斜线后跟斜线替换包名中的点,然后再委托加载Class对象的类加载器来查找资源。 假设测试类在com.jdojo.test包中,以下调用:
Test.class.getResource("resources/test.config");
会被转换成
Test.class.getClassLoader().getResource("com/jdojo/test/resources/test.config");

2. 在JDK 9 中访问资源

在JDK 9之前,可以从类路径上的任何JAR访问资源。 在JDK 9中,类和资源封装在模块中。 在第一次尝试中,JDK 9设计人员强制执行模块封装规则,模块中的资源必须对该模块是私有的,因此它们只能在该模块内的代码中访问。 虽然这个规则在理论上看起来很好,但是对于跨模块共享资源的框架和加载的类文件作为来自其他模块的资源,就会带来问题。 为了有限地访问模块中的资源,做了一些妥协,但是仍然强制执行模块的封装。 JDK 9包含三类资源查找方法:
java.lang.Class
java.lang.ClassLoader
java.lang.Module
Class和ClassLoader类没新增任何新的方法。 Module类包含一个getResourceAsStream(String name)方法,如果找到该资源,返回一个InputStream;否则返回null。

声明: 本文由金丝燕网原创编译,转载请保留链接: jdk9新特征系列(二):访问资源,更多交流请加群:278721352