一、通过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; } |
相关推荐
这种方法适用于全局的系统资源,从系统的类路径中加载 `.properties` 文件。示例: ```java InputStream in = ClassLoader.getSystemResourceAsStream(name); Properties p = new Properties(); p.load(in); `...
这个"Java加载配置文件工具类"很可能是为了解决这个问题而创建的一个实用工具,帮助开发者更方便、高效地处理配置文件。配置文件通常以.properties或.xml格式存在,用于存储应用程序的参数、配置项等。 配置文件的...
总之,通过Java的静态代码块和类加载器,我们可以有效地管理和加载资源文件,特别是属性配置文件,确保在程序启动时即完成初始化工作,提升应用性能。这种技术在大型复杂系统中尤其常见,因为它能够保证配置的正确性...
// 加载资源文件 props.load(inputStream); // 访问属性 String propertyValue = props.getProperty("key"); System.out.println("Property value: " + propertyValue); } catch (Exception e) { e....
以上就是Java中加载配置文件的一些常见方法,每种方法都有其适用的场景和优缺点。选择哪种方式取决于你的项目需求,如配置文件的位置、格式以及是否需要进行国际化处理等因素。在实际开发中,应根据具体情况灵活选择...
在Java编程中,有时我们需要动态地加载外部JAR文件,并执行其中特定的类方法,这在插件系统、模块化应用或动态扩展性需求中尤为常见。本篇将详细讲解如何实现这一目标。 首先,理解JAR(Java Archive)文件是Java...
在Java应用开发中,特别是Web应用程序的构建过程中,资源文件(如配置文件、属性文件等)的加载是必不可少的一部分。本文将重点探讨Java环境下不同方式下的文件加载方法,尤其关注在Spring框架下的实践与应用。 ###...
### Java读取文件方法大全:读取File流等技术 在Java中,读取文件是一项基本且重要的操作,它可以通过多种方式实现,如字节流、字符流和基于行的读取。下面将详细介绍这些方法: #### 字节级读取:`...
在Java编程中,解析资源文件是一项常见的任务,它涉及到读取和操作项目中的文本、配置、图片等非代码数据。本教程将深入讲解如何在Java中处理资源文件,以及使用jbom解析工具的相关知识。 首先,理解资源文件的定位...
Java热加载Class文件是开发者在调试和优化代码时非常实用的一种技术,它允许开发者在不重启JVM的情况下更新和替换已加载的类,极大地提高了开发效率。本文将深入探讨Java热加载Class文件的相关知识点。 首先,理解...
2. **Java加载3D模型**: - 在Java中,我们可以使用各种库来解析和加载这些3D模型,如J3D(Java 3D)、JMonkeyEngine或j3mdk等。这些库提供了API,可以读取OBJ和STL文件,并将数据转化为Java对象,以便进一步处理。...
在Android开发中,加载资源文件,尤其是PDF文档,是一个常见的需求。这个"加载资源文件的PDF"项目提供了一个完美的示例,演示了如何在Android应用中实现PDF的加载、缩放以及保持清晰度。以下是对这个项目的详细解析...
本篇文章将详细探讨如何在Java中正确地从JAR包中加载资源文件,并提供相应的源码示例。 首先,理解Java类路径(classpath)是关键。类路径是指Java虚拟机(JVM)查找.class文件和其他资源文件的路径。当你运行一个...
加载文件资源的三种方式 ~1.从classpath根目录下加载指定名称的文件 2.从classpath根目录下加载指定名称的文件 3. 从classpath根目录下加载指定名称的文件 4. 获取当前文件的绝对路径
读取资源文件的过程包括将资源文件读入到输入流中,然后利用`Properties`类的`load()`方法加载到内存。具体步骤如下: 1. **创建Properties实例**:首先,创建一个`Properties`对象实例,这将用于存储从资源文件中...
利用swt中的一个获取图片的类SwingResourceManager 来解决将程序打为使用java打包之后,生成的jar包中图片找不着的。这是因为通过class.getResource()方法在IDEA中运行的路径和生成jar包获取的的路径是不同的。打成...
Java加载properties文件实现方式详解 Java加载properties文件是Java开发中常见的场景,properties文件是一种配置文件,用于存储应用程序的配置信息。Java提供了多种方式来加载properties文件,本文将详细介绍Java...
System.err.println("无法加载资源文件: " + e.getMessage()); } ``` 4. **国际化(i18n)**: `.properties`文件也常用于实现应用程序的国际化。每个语言版本都有一个相应的资源文件,例如`messages_en....
本文将详细介绍Java中资源文件的基本概念、加载机制以及如何使用Resource Bundle进行国际化和本地化。 Java中的资源文件(Resource Bundle)是实现国际化和本地化的强有力工具。通过本文的介绍,读者应该能够了解...
处理配置文件对于Java程序员来说再常见不过了,不管是Servlet,Spring,抑或是Structs,都... 在了解了Java加载资源文件的机制后,以上这两个问题便迎刃而解了。 对于第一个问题,答案是:请将你的资源文件放在c