系列文章目录
前言
一、为什么大部分的框架都要自己弄一个Resource类呢
我们先从第一行进行分析
//2.读取配置文件
reader = Resources.getResourceAsReader(resource);//2.读取配置文件
这个类是读取资源类,具体完成将xml文件加载生成一个Reader,这里我就有一个疑问,为什么大部分的框架都要自己弄一个Resource类呢?加载一个文件或URL资源都是比较简单的?真是这样子吗?我们来看看Resource.class的源代码:
/**
* A class to simplify access to resources through the classloader.
* 一个简单的通过类加载器访问资源的类
*
* @author Clinton Begin
*/
public class Resources {
//类加载器包装类?为什么,我们接后面再看
private static ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper();
/**
* Charset to use when calling getResourceAsReader.
* null means use the system default.
* 字符集,默认使用系统的,考虑得比较周全,一般我们都没有考虑或直接写死
*/
private static Charset charset;
public static URL getResourceURL(ClassLoader loader, String resource) throws IOException {
//把返回的过程委托给了classLoaderWrapper
URL url = classLoaderWrapper.getResourceAsURL(resource, loader);
if (url == null) {
throw new IOException("Could not find resource " + resource);
}
return url;
}
public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
//把返回的过程委托给了classLoaderWrapper
InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
if (in == null) {
throw new IOException("Could not find resource " + resource);
}
return in;
}
/**
* Returns a resource on the classpath as a Properties object
* 得到一个资源的Properties对象,资源是.properties文件
* @param resource The resource to find
* @return The resource
* @throws java.io.IOException If the resource cannot be found or read
*/
public static Properties getResourceAsProperties(String resource) throws IOException {
Properties props = new Properties();
try (InputStream in = getResourceAsStream(resource)) {
props.load(in);
}
return props;
}
public static Properties getResourceAsProperties(ClassLoader loader, String resource) throws IOException {
Properties props = new Properties();
try (InputStream in = getResourceAsStream(loader, resource)) {
props.load(in);
}
return props;
}
public static Reader getResourceAsReader(String resource) throws IOException {
Reader reader;
if (charset == null) {
reader = new InputStreamReader(getResourceAsStream(resource));
} else {
reader = new InputStreamReader(getResourceAsStream(resource), charset);
}
return reader;
}
public static Reader getResourceAsReader(ClassLoader loader, String resource) throws IOException {
Reader reader;
if (charset == null) {
reader = new InputStreamReader(getResourceAsStream(loader, resource));
} else {
reader = new InputStreamReader(getResourceAsStream(loader, resource), charset);
}
return reader;
}
public static File getResourceAsFile(String resource) throws IOException {
return new File(getResourceURL(resource).getFile());
}
public static File getResourceAsFile(ClassLoader loader, String resource) throws IOException {
return new File(getResourceURL(loader, resource).getFile());
}
这个资源类里最重要的只有几个方法,就是实际执行的方法,这里面有涉及另外一个类ClassLoaderWrapper ,看上去所有这些实际加载都是
我们再来看看ClassLoaderWrapper是如何去实际加载资源的
/**
* A class to wrap access to multiple class loaders making them work as one
* 一个包装访问多个类加载器使它看起来像在访问一个一样加载资源
*
* @author Clinton Begin
*/
public class ClassLoaderWrapper {
ClassLoader defaultClassLoader;
ClassLoader systemClassLoader;
ClassLoaderWrapper() {
try {
systemClassLoader = ClassLoader.getSystemClassLoader();
} catch (SecurityException ignored) {
// AccessControlException on Google App Engine
}
}
…
//核心方法之一,其它一样
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
for (ClassLoader cl : classLoader) {
if (null != cl) {
// try to find the resource as passed
InputStream returnValue = cl.getResourceAsStream(resource);
// now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
if (null == returnValue) {
returnValue = cl.getResourceAsStream("/" + resource);
}
if (null != returnValue) {
return returnValue;
}
}
}
return null;
}
//核心方法
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[]{
classLoader,
defaultClassLoader,
Thread.currentThread().getContextClassLoader(),
getClass().getClassLoader(),
systemClassLoader};
}
}
这个类做了一件什么事情呢?就是按顺序找到一个合适的类加载器,去加载相应的资源。最核心的方法就是最后一个ClassLoader[] getClassLoaders(ClassLoader classLoader),它返回自己顺序的类加载器列表,一般情况下classLoader和defaultClassLoader都为null,所以使用最多的就是 Thread.currentThread().getContextClassLoader()这个类加载器,这里涉及一个基础知识点JVM类加载过程模模型。