我们有很多方法加载资源文件,比如用ClassLoader.getResourceAsStream、ClassLoader.getSystemResourceAsStream或者Class.getResourceAsStream,那么他们之间有什么区别呢?
加载资源文件和加载类是一样原理。首先我们看看类加载器,然后就能理解资源文件是怎么加载的了。
什么是类加载器?
类加载器(ClassLoader)指将类加载到虚拟机中的代码模块,所有的类必须通过加载器被加载到JVM中。JVM规范将累加在的过程外置于JVM实现,让应用程序自己决定如何获取所需类,这种机制位类层次划分,热加载,模块化奠定了基础。
类加载器分类
类加载器主要分为:
- 启动类加载器(Bootstrap ClassLoader):主要负责加载\lib目录中或者-Xbootclasspath中指定的,并且被虚拟机识别的类库加载到VM中。这个加载器是JVM自身的一部分,用本地代码实现的(openjdk中源码位于hotspot/src/share/vm/classfile/classLoader.cpp中),无法直接被java代码引用。
- 扩展类加载器(Extension ClassLoader):主要负责加载jdk扩展类库\lib\ext或者java.ext.dirs系统属性指定的目录中jar文件,由sun.misc.Launcher$ExtClassLoader实现
- 系统类加载器(System ClassLoader):用于加载CLASSPATH中指定的类,由sun.misc.Launcher$AppClassLoader实现。该类即ClassLoader.getSystemLoader()的返回值,是应用程序默认的类加载器。
- 自定义加载器(User ClassLoader):用户可以自定义自己的类加载器
在介绍完类加载器后,下面介绍3种加载资源文件方式。
3种加载资源文件方式
- ClassLoader.getResourceAsStream: 如果是自定义的加载器,会先使用父类加载器来查找;如果为空,再使用BootClassLoader加载器(顶层加载器,这在类加载器分类中有描述)来查找;如果又未找到,则调用findResource方法查找(ClassLoder是没有实现该方法的,对于自定义的加载器需要实现该方法)
- ClassLoader.getSystemResourceAsStream: 使用的系统类加载器(AppClassLoader)来查找
- Class.getResourceAsStream: 使用加载该类的类加载器来查找。该方法首先会将类的包路径转换为“/",以表示资源文件的路径,然后再传给类加载器。
这3中加载资源的位置,都是从System.getProperty("java.class.path")得到的目录或者jar里开始查找的,也就是说,如果遇到目录,会从目录开始查找资源,但是如果是jar,则从jar里为开始路径查找。
例如:classpath是WEB-INF\classes和 lib\activation-1.1.jar。通过ClassLoader.getSystemResourceAsStream("dataimport.properties")代码加载资源文件,那么dataimport.properties资源文件可以放到classes文件夹下,或者activation-1.1.jar包里面。
参考网站:http://jiangbo.me/blog/2012/02/14/jetty-classloader/