`

ClassLoader与资源文件加载

 
阅读更多
深刻理解java的配置环境以及java的执行过程对做好开发是十分重要的。
类加载器ClassLoader 便是其中非常重要的概念。

本文简单并演示Java类加载器的一些特点,不妥之处,敬请指出。

背景:
A.java 引用 了B.jar 中的一个文件,B.jar 包中的C.class 使用了C.class.getResourceAsStream("/jdbc.xml")获取资源文件。 B.jar 做一个独立的功能的工具,使用方只要提供对应的jdbc.xml 配置文件即可在dev qa prod 各个环境使用啦。
但是问题来了,在web下和java命令行情况下,jdbc.xml 文件放置的位置大不相同,因为web 和java命令下 B.jar 中加载C.class的类加载器不同!


类加载器的分类:
1、启动类加载器(Bootstrap ClassLoader) 这个类有c++语言实现,是虚拟机的一部分。
2、所有其他类加载器。其他类加载器都继承抽象类java.lang.ClassLoader。


做为java的大部分项目,都是有以下三类类加载器加载的:
1、启动类加载器。加载的内容为:<JAVA_HOME/lib 目录中的jar包。
2、扩展类加载器。加载的内容为:java.ext.dirs 系统变量指定的路径中所有类库。实现为:sun.misc.Launcher$ExtClassLoader 实现。
3、应用类加载器。实现为:sun.misc.Launcher$AppClassLoader。负责加载用户类路径上指定的类库。

下面我们看个例子:

package org.job.user;

import org.apache.commons.lang.StringUtils;

public class Test {
	public static void main(String[] args) {
       System.out.println(Thread.currentThread().getContextClassLoader());
       System.out.println(StringUtils.class.getClassLoader());
       
       System.out.println(StringUtils.class.getResource("/"));
       System.out.println(Test.class.getResource("/"));
       
       System.out.println(StringUtils.class.getResourceAsStream("/jdbc.xml"));
       System.out.println(Test.class.getResourceAsStream("/jdbc.xml"));
	}
}



此时如果大家到Test.java 所在的目录,执行javac Test.java 会报错:


为什会报错,因为org.apache.commons.lang.StringUtils 找不到,当前AppClassLoader 找不到StringUtils 类的路径。

找到StringUtils 可以通过指定-classpath .;D:\DevPlatform\m2localRepository\commons-lang\commons-lang\2.5\commons-lang-2.5.jar 来找到。


大家注意到输出:
sun.misc.Launcher$AppClassLoader@19821f
sun.misc.Launcher$AppClassLoader@19821f
file:/E:/spring/spring-aop-aspectj/target/test-classes/
file:/E:/spring/spring-aop-aspectj/target/test-classes/
java.io.BufferedInputStream@1fb8ee3
java.io.BufferedInputStream@61de33
Test.class 和StringUtils.class 都是通过同一个类加载器(AppClassLoader)加载的。另外 通过Test.class.getResourceAsStream("/jdbc.xml") 找到了jdbc.xml 文件,jdbc.xml 文件在E:\spring\spring-aop-aspectj\src\test\java 也即是我执行java 和 javac 的位置。
这说明:AppClassLoader 的根目录在执行环境的目录。


下一步我们演示通过ExtClassLoader 加载,即通过-Djava.ext.dirs=D:\DevPlatform\m2localRepository\commons-lang\commons-lang\2.5 来加载commons-lang-2.5.jar包。



从上面的输出我们看到Test.class 和 StringUtils.class 的类加载器不同了,另外 System.out.println(StringUtils.class.getResourceAsStream("/jdbc.xml")); //没有找到对应的资源文件
       System.out.println(Test.class.getResourceAsStream("/jdbc.xml")) //找到了对应的资源文件

为什么StringUtils.class 找不到对应的资源文件了,因为getResourceAsStream 是通过委托对应的类加载器来加载的,"/jdbc.xml" 通过不同的类加载器来加载,对于的资源文件的位置是不同的。

我在commons-lang-2.5.jar 包所在目录创建com 并在其下建立jdbc.xml 文件,继续运行结果如下:



看到上面的输出,一切都不言而喻。

总结:
对于Class.getResourceAsStream("/*.*") 是通过委托给对应的ClassLoader来加载的,其对应的资源文件的根目录为:
ExtClassLoader: 为java.ext.dirs 指定的目录下的所以目录。优先使用相应jar包的路径对应的根目录。比如java.ext.dirs=/home/q/,那么其根目录为/home/q/*dir。

AppClassLoader: 执行java javac 命令的目录。

注意:AppClassLoader寻找跟资源文件优先使用java.ext.dirs 指定的资源文件,如果没有才会到 命令执行的目录下寻找。 另外java.ext.dirs 指定的资源文件 最好不要有多个重名的文件,否则将不确定使用的是哪一个。
验证留给大家吧
  • 大小: 5.5 KB
  • 大小: 5.9 KB
  • 大小: 7.4 KB
  • 大小: 5.8 KB
0
1
分享到:
评论

相关推荐

    classloader类加载器_基于java类的加载方式详解

    下面小编就为大家带来一篇classloader类加载器_基于java类的加载方式详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    Java加载资源文件的两种方法

    处理配置文件对于Java程序员来说再常见不过了,不管是Servlet,Spring,抑或是Structs,都...  在了解了Java加载资源文件的机制后,以上这两个问题便迎刃而解了。  对于第一个问题,答案是:请将你的资源文件放在c

    ClassLoaderTest:测试如何正确关闭类加载器,以便可以关闭基础jar文件上的文件句柄

    ClassLoaderTest 测试自定义的URLClassLoader以加载类 测试如何正确关闭类加载器。 测试如何使用反射关闭JarFile来修复资源泄漏。

    JVM中编译Class、内存回收、多线程原理和使用

    class文件通常由类加载器(ClassLoader)来完成加载;class的执行在Sun JDK中有解释执行和编译为机器码执行两种方式,其中编译为机器码又分为client和server两种模式。Sun JDK为了提升class的执行效率,对于解释执行...

    eclipse-project-loader:ClassLoder 用于Eclipse项目中资源文件的高效引用

    但是src/main/resources等资源目录只有在Eclipse项目重载时才会反映在target/classes ,所以如果在Eclipse外编辑资源文件,每次都需要重载Eclipse项目... 如果找到的 Java 类文件以外的资源位于target/classes ,...

    Tomcat 类加载器的实现方法及实例代码

    Tomcat 内部定义了多个 ClassLoader,以便应用和容器访问不同存储库中的类和资源,同时达到应用间类隔离的目的。 1. Java 类加载机制 类加载就是把编译生成的 class 文件,加载到 JVM 内存中(永久代/元空间)。 类...

    day020-继承加强和设计模式代码和笔记.rar

    2、InputStream is = classLoader.getResourceAsStream("文件路径/文件名");//通过当前线程的类加载器获取流对象,如果是源文件夹,直接文件名 建议用当前线程类的加载器方式获取流,线程安全问题 ...

    Android插件框架Android-Plugin-Framework.zip

    2、支持在插件中通过R文件使用宿主程序中的资源,暂不支持插件资源文件中直接使用宿主程序中的资源。但是支持间接使用。 例如在上述“已支持的功能”6中描述的,实际就是间接使用。 后续需要解决的问题: ...

    spring源代码

    通过虚拟目录获取文件资源 VirtualFile testFile = home.getChild("test.txt"); ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver....

    Android动态替换Application实现

    最近做一些Android方面的优化工作,大家知道Android的ClassLoader在加载dex文件的过程中,而AndroidManifest的Application类就在dex文件中,Application通常会做一些全局的初始化工作,在加载dex之前,我们需要替换...

    jcrypt:加密的内存Classloader loader + Builder

    包括用于构建文件的向导(检查发行版,jCrypt.jar)。 Bin.jar必须位于jCrypt.jar的工作目录中 对输入档案进行加密,并将其写入Bin.jar的副本中,并在Extra字段中设置加密密钥,初始化向量,加密资源和mainclass。 ...

    Java JDK 7学习笔记(国内第一本Java 7,前期版本累计销量5万册)

    chapter15 反射与类加载器 499 15.1 运用反射 500 15.1.1 class与.class文档 500 15.1.2 使用class.forname() 502 15.1.3 从class获得信息 503 15.1.4 从class建立对象 506 15.1.5 操作对象方法与成员 ...

    高级java笔试题-itresource:程序开发技术资源集合

    从Jar文件中动态加载类 ] () [ Java并发源码分析 - ThreadPoolExecutor ] () [ java ClassLoader 基本原理 ] () [ 解决eclipse显示jar源代码中文乱码问题 ] () [ 使用 RMI + ZooKeeper 实现远程调用框架 ] () [ Java...

    Spring.3.x企业应用开发实战(完整版).part2

    3.3.2 资源加载 3.4 BeanFactory和ApplicationContext 3.4.1 BeanFactory介绍 3.4.2 ApplicationContext介绍 3.4.3 父子容器 3.5 Bean的生命周期 3.5.1 BeanFactory中Bean的生命周期 3.5.2 ApplicationContext中Bean...

    Spring3.x企业应用开发实战(完整版) part1

    3.3.2 资源加载 3.4 BeanFactory和ApplicationContext 3.4.1 BeanFactory介绍 3.4.2 ApplicationContext介绍 3.4.3 父子容器 3.5 Bean的生命周期 3.5.1 BeanFactory中Bean的生命周期 3.5.2 ApplicationContext中Bean...

    java 面试题 总结

    finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。 13、sleep() 和 wait() 有什么区别? sleep是线程类(Thread)的...

    JAVA面试题最全集

    37.classloader中,JDK的API、Classpath中的同web-inf中的class加载方式有什么区别? 38.列举三种以上垃圾回收算法,并比较其优缺点? 39.编写代码实现一个线程池 40.描述一下JVM加载class文件的原理机制? 41....

    超级有影响力霸气的Java面试题大全文档

    finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。 16、sleep() 和 wait() 有什么区别? sleep是线程类(Thread)...

    light-jpf:轻量级Java插件框架

    轻量级Java插件框架1.特点简单的API 使用自定义Java类加载器进行沙箱测试使用Maven构建插件2.用法2.1创建插件创建实现ljpf.Plugin接口的... }} 为相应的插件创建描述符文件,并将其放置在项目资源中。 描述符文件必须具

    JAVA核心知识点整理(有效)

    25 JAVA8 与元数据.................................................................................................................................25 2.4. 垃圾回收与算法 .................................

Global site tag (gtag.js) - Google Analytics