一、通过Class:getResource()加载资源
通过Class类的public java.net.URL getResource(String name)
public java.net.URL getResource(String name) { name = resolveName(name); ClassLoader cl = getClassLoader0(); if (cl==null) { // A system class. return ClassLoader.getSystemResource(name); } returncl.getResource(name); } |
通过Class类的getResource和通过ClassLoader的类加载资源的主要区别在于resolveName这个方法,我们来看下它的实现:
private String resolveName(String name) { if (name == null) { returnname; } if (!name.startsWith("/")) { Class<?> c = this; while (c.isArray()) { c = c.getComponentType(); } String baseName = c.getName(); intindex = baseName.lastIndexOf('.'); if (index != -1) { name = baseName.substring(0, index).replace('.', '/') +"/"+name; } } else { name = name.substring(1); } returnname; } |
resolveName方法,如果是资源名是以/开头的绝对路径,例如/a/b/c,则返回a/b/c给ClassLoader调用;
如果资源名不是以/开头的绝对路径,例如a/b/c,则返回当前类grucee.test.Main的包路径grucee/test加上/+a/b/c,最后的结果就是grucee/test/a/b/c。
我们来看两个示例:
资源文件如下图:
代码
publicstaticvoid main(String[] args) throws IOException { String absolutePath = "/test.properties"; String relativePath = "test.properties";
InputStream absoluteIn = Main.class.getResourceAsStream(absolutePath); InputStream relativeIn = Main.class.getResourceAsStream(relativePath);
//假设编译后的文件按照包结构放置在bin目录(eclipse默认) //传绝对路径加载的是相对于bin目录的文件:bin/test.properties Properties absoluteProp = new Properties(); absoluteProp.load(absoluteIn); System.out.println(absoluteProp.getProperty("path"));
//传相对路径加载的是相对于Main.class所在目录的文件:bin/grucee/test/test.properties Properties relativeProp = new Properties(); relativeProp.load(relativeIn); System.out.println(relativeProp.getProperty("path")); } |
二、通过ClassLoader:getResource()加载资源
系统有哪些ClassLoader
1).Bootstrap Loader(引导类加载器):加载System.getProperty("sun.boot.class.path")所指定的路径或jar。
2).Extended Loader(标准扩展类加载器ExtClassLoader):加载System.getProperty("java.ext.dirs")所指定的路径或jar。在使用Java运行程序时,也可以指定其搜索路径,例如:java -Djava.ext.dirs=d:\projects\testproj\classes HelloWorld
3).AppClass Loader(系统类加载器AppClassLoader):加载System.getProperty("java.class.path")所指定的路径或jar。在使用Java运行程序时,也可以加上-cp来覆盖原有的Classpath设置,例如: java -cp ./lavasoft/classes HelloWorld
4).自定义类加载器
ExtClassLoader和AppClassLoader在JVM启动后,会在JVM中保存一份,并且在程序运行中无法改变其搜索路径。如果想在运行时从其他搜索路径加载类,就要产生新的类加载器。
线程上下文类加载器
线程上下文类加载器(context class loader)是从 JDK 1.2 开始引入的。类 java.lang.Thread中的方法 getContextClassLoader()和setContextClassLoader(ClassLoader cl)用来获取和设置线程的上下文类加载器。如果没有通过 setContextClassLoader(ClassLoader cl)方法进行设置的话,线程将继承其父线程的上下文类加载器。Java 应用运行的初始线程的上下文类加载器是系统类加载器。在线程中运行的代码可以通过此类加载器来加载类和资源。
前面提到的类加载器的代理模式并不能解决 Java 应用开发中会遇到的类加载器的全部问题。Java 提供了很多服务提供者接口(Service Provider Interface,SPI),允许第三方为这些接口提供实现。常见的 SPI 有 JDBC、JCE、JNDI、JAXP 和 JBI 等。这些 SPI 的接口由 Java 核心库来提供,如 JAXP 的 SPI 接口定义包含在 javax.xml.parsers包中。这些 SPI 的实现代码很可能是作为 Java 应用所依赖的 jar 包被包含进来,可以通过类路径(CLASSPATH)来找到,如实现了 JAXP SPI 的 Apache Xerces所包含的 jar 包。SPI 接口中的代码经常需要加载具体的实现类。如 JAXP 中的 javax.xml.parsers.DocumentBuilderFactory类中的 newInstance()方法用来生成一个新的 DocumentBuilderFactory的实例。这里的实例的真正的类是继承自 javax.xml.parsers.DocumentBuilderFactory,由 SPI 的实现所提供的。如在 Apache Xerces 中,实现的类是 org.apache.xerces.jaxp.DocumentBuilderFactoryImpl。而问题在于,SPI 的接口是 Java 核心库的一部分,是由引导类加载器来加载的;SPI 实现的 Java 类一般是由系统类加载器来加载的。引导类加载器是无法找到 SPI 的实现类的,因为它只加载 Java 的核心库。它也不能代理给系统类加载器,因为它是系统类加载器的祖先类加载器。也就是说,类加载器的代理模式无法解决这个问题。
线程上下文类加载器正好解决了这个问题。如果不做任何的设置,Java 应用的线程的上下文类加载器默认就是系统上下文类加载器。在 SPI 接口的代码中使用线程上下文类加载器,就可以成功的加载到 SPI 实现的类。线程上下文类加载器在很多 SPI 的实现中都会用到。
加载资源的流程
用ClassLoader加载配置文件时,路径均不能以"/"开头,在查找时直接在classpath下进行查找。
查看源代码:
public URL getResource(String name) { URL url; if (parent != null) { url = parent.getResource(name); } else { url = getBootstrapResource(name); } if (url == null) { url = findResource(name); } returnurl; } |
假设我们没有自定义类加载器,并且我们调用的是系统类加载器的getResource,那么该ClassLoader就是AppClassLoader的实例,并且通过上述方法,依次会调用:
AppClassLoader:getResource->ExtClassLoader:getResource->getBootstrapResource()。也就是分别在加载启动类、扩展类、系统类的路径下寻找资源文件,和类加载采用相同的双亲委派机制。
并不是所有的类加载都符合双亲委派机制,因此类中加载的资源文件也不是都符合双亲委派机制。所以加载资源的时候,也需要用到线程上下文类加载器。我们通常使用下面的代码加载资源文件(通常使用ClassLoader的getResource(),它和类加载思路一致,因此更好理解):
privatestatic InputStream loadConfigFile() { //先使用当前类的类加载器查找资源 InputStream in = FileLogReader.class.getClassLoader().getResourceAsStream(LoggerConstants.FILE_LOG_PATH); if (in == null) { //查找不到资源时,使用线程上下文的类加载器查找资源 in = Thread.currentThread().getContextClassLoader() .getResourceAsStream(LoggerConstants.FILE_LOG_PATH); } returnin; } |
相关推荐
本案例是一个通过静态代码块获取资源属性文件的代码块,从而来提高应用性能。。
加载文件资源的三种方式 ~1.从classpath根目录下加载指定名称的文件 2.从classpath根目录下加载指定名称的文件 3. 从classpath根目录下加载指定名称的文件 4. 获取当前文件的绝对路径
利用swt中的一个获取图片的类SwingResourceManager 来解决将程序打为使用java打包之后,生成的jar包中图片找不着的。这是因为通过class.getResource()方法在IDEA中运行的路径和生成jar包获取的的路径是不同的。打成...
处理配置文件对于Java程序员来说再常见不过了,不管是Servlet,Spring,抑或是Structs,都... 在了解了Java加载资源文件的机制后,以上这两个问题便迎刃而解了。 对于第一个问题,答案是:请将你的资源文件放在c
java加载obj,stl模型资源,html页面展示。 部署即可运行,提供基础数据样例展示
主要介绍了Java加载properties文件实现方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
web开发时,修改java文件后,无须重启服务器便可自动加载修改之后的java文件。本资源包含jrebel.jar及其使用说明。
Jar包中如何正确地加载资源文件博文中用到的测试项目源码 http://codepub.cn/
今天偶然看到一篇关于tomcat加载servlet的文章,不由得想起了java加载资源文件的路径问题,资源文件可以使xml,properties,图片等,可以是任何文件
我们将详细讲解字节码文件的结构、语法和格式,以及字节码指令的定义和应用,并通过大量实例进行编程详解,帮助开发人员深入了解Java字节码的使用方法和技巧。 在类加载方面,我们将深入探讨Java程序的类加载原理和...
Java加载资源文件的两种方法getResource与getResourceAsStream
Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...
该类加载器用于从指向 JAR 文件和目录的 URL 的搜索路径加载类和资源。如果不是以该字符结束,则认为该 URL 指向一个将根据需要打开的 JAR 文件pac
Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...
压缩包里面包含三个文件: cors-filter-2.4.jar java-property-utils-1.9.1.jar 必看文档.txt 在安装好Geoserver后可以看一下“必看文档.txt”,修改相应配置
Qt加载自己的字体,不用系统提供的QFontComboBox
Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java...
Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java...
ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
JAVA 中单个或多个下载服务器上带超链接的文件 并压缩后下载, 如:http://172.16.10.24/recordwav/20150625/48/20150625140223_48_8003_8002_to_18064000047.wav http://www.baidu.com/img/test.png 此资源中还...