Java 资源加载
04 Nov 2021Java 运行时会用到一些非代码的资源类文件, JVM 本身提供了几种方式来加载资源, 常用的 Spring 也提供了相应的加载资源文件的方式. 如果不了解这些加载资源的方式的细节, 实际开发时就没法按照你自己的意愿来灵活加载资源, 经常会遇到加载不到或者加载到错误资源的问题. 常见的两类加载资源的方式就是上面提到的基于 JVM 和 Spring 提供的方式来加载资源.
JVM
JVM 提供的加载资源的方式又可以分为两类, 一个是通过 ClassLoader
另一个是通过 Class
, 都是到 classpath
中配置的地址中查找资源. 两者区别不是很大, 通过 Class
来查找资源最终也是调用到 ClassLoader
来查找的, 只是 Class
默认是在对应类所在的目录下来查找的, 如果你要从根目录来查找就需要在查找的资源前加上 /
, 要注意的是 ClassLoader
来查找资源的时候是不支持以 /
开头的资源名的 [1]. ClassLoader
有 getResource
和 getResources
两个方法, 如果指定的资源名有多个资源时, 前者会返回找到的第一个资源, 后者会返回所有.
前面提到, Class
和 ClassLoader
都是从 classpath
中去查找资源, 我们知道, classpath
中可以配置文件目录地址, 也可以配置 jar 包, 相对应的, JVM 实现时分别使用了 FileLoader
和 JarLoader
来查找资源. 这两个 Loader 对于空字符串的处理是不一样的, FileLoader
会返回根目录, JarLoader
则找不到对应资源, 具体实现可以看下源码,入口是 URLClassLoader
, 最终会使用 sun.misc.URLClassPath
查找资源 [2].
Spring
JVM 只能从 classpath
中查找资源, Spring 则在此基础上增加了从文件地址, 网络, jar 等地方加载, 通过在资源名前指定 protocol 来区分 [3]. 常见的 protocol 有:
classpath:
: 同ClassLoader
的getResource
classpath*:
: 同ClassLoader
的getResources
, 同时还支持 ant 风格的通配符 [4], 具体实现上就是先把第一个通配符前面的字符串取出来调用ClassLoader
的getResources
方法, 然后再在找到的资源下面遍历查找 [5, 6]file:
: 从本地文件里查找, 支持 ant 风格的通配符jar:
: 从 jar 包查找, 支持 ant 风格的通配符zip:
: 从 zip 压缩包查找, 支持 ant 风格的通配符http://
: 从网络里加载
[1] https://stackoverflow.com/questions/47900677/where-does-leading-slash-in-java-class-loader-getresource-leads-to
[2] https://stackoverflow.com/questions/45624909/java-empty-path-convention-especially-that-used-in-classloader-getresources
[3] https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/resources.html
[4] https://stackoverflow.com/questions/2952196/ant-path-style-patterns
[5] https://stackoverflow.com/questions/13994840/what-is-the-difference-between-classpath-and-classpath-in-spring-xml
[6] https://stackoverflow.com/questions/3294423/spring-classpath-prefix-difference