1 概述
在我们使用Mybatis的时候都需要将配置文件转换成InputStream,这使用我们通常是使用Resources的getResourceAsStream函数。通过查看Resources源码的注释我们也可以发现,Resources提供了通过类加载器获取资源的功能
2 ClassLoaderWrapper类
查看Resources源码,可以看见其拥有一个ClassLoaderWrapper静态属性,再分析Resrouoces源码之前,我们先来看一看这个ClassLoaderWrapper的实现及作用。
2.1 作用
ClassLoaderWrapper是一个ClassLoader的包装器,里面包含了多个ClassLoader对象,通过调整多个类加载器的使用顺序,ClassLoaderWrapper 可以确保返回给系统使用的是正确的类加载器。ClassLoaderWrapper 会按照指定的顺序依次检测其中封装的ClassLoader对象,并从中选取第一个可用的ClassLoader 对象。
2.2 属性
ClassLoader defaultClassLoader; //默认类加载器
ClassLoader systemClassLoader; //系统类加载器
2.3 核心方法
(1)getClassLoaders:获取类加载器的数组
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[]{
//参数指定的类加载器
classLoader,
//系统指定的默认加载器
defaultClassLoader,
//当前线程绑定的类加载器
Thread.currentThread().getContextClassLoader(),
//当前类使用的类加载器
getClass().getClassLoader(),
//系统类加载器
systemClassLoader};
}
(2)classForName:使用加载器加载一个指定名称的类
Class<?> classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {
//遍历类记载器
for (ClassLoader cl : classLoader) {
if (null != cl) {
try {
//获取到指定名称的类对象
Class<?> c = Class.forName(name, true, cl);
if (null != c) {
return c;
}
} catch (ClassNotFoundException e) {
// we'll ignore this until all classloaders fail to locate the class
}
}
}
throw new ClassNotFoundException("Cannot find class: " + name);
}
(3)getResourceAsURL:从当前类路径获取资源的URL
URL getResourceAsURL(String resource, ClassLoader[] classLoader) {
URL url;
//遍历类记载器
for (ClassLoader cl : classLoader) {
if (null != cl) {
//获取资源的URL
url = cl.getResource(resource);
if (null == url) {
url = cl.getResource("/" + resource);
}
if (null != url) {
return url;
}
}
}
return null;
}
(4)getResourceAsStream:获取资源的输入流
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
//遍历类记载器
for (ClassLoader cl : classLoader) {
if (null != cl) {
//获取资源的输入流
InputStream returnValue = cl.getResourceAsStream(resource);
if (null == returnValue) {
returnValue = cl.getResourceAsStream("/" + resource);
}
if (null != returnValue) {
return returnValue;
}
}
}
return null;
}
通过上面的源码我们可以发现,ClassLoaderWrapper其实就是使用合适的类加载器来获得需要的文件数据。
3 Resources 的函数
针对Resources的函数其实大部分都是直接调用ClassLoaderWrapper的函数来实现的,这里我们仅仅对getResourceAsProperties进行分析,其余的函数都比较简单。
public static Properties getResourceAsProperties(ClassLoader loader, String resource) throws IOException {
Properties props = new Properties();
InputStream in = getResourceAsStream(loader, resource);
props.load(in);
in.close();
return props;
}
我们可以看见这里直接使用了Properties的load函数来从输入流中获取到Properties对象。
上面就是我们对Resources源码的分析,后面将继续分析其余工具类的源码,欢迎交流。