- 前面我们大概了解了spring容器的各个功能,可能有些迷糊,说实在的我也迷糊,不过不打紧,接下来来看看每个功能的具体的实现逻辑过程:
- 在看之前我们先来看一段熟知的代码,代码如下:
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
简单的一行代码,大家都知道,从代码我们可以看到:
- new ClassPathResource()首先是去定位我们创建xml文件的所在位置.
- 然后就是相应的资源转化过程,将资源转化为Resource对象.
- 然后new XmlBeanFactory()这里需要一个resource对象.
- 加载对应的resource的文件等,至于用什么样的方法去加载resource文件,接下来看;
这里只是简单的猜测,具体怎么样的,在这之前我们还需了解一个东西,就是spring是如何将我们的配置文件进行封装的,直击Resource类
原来该Resource是一个接口,我们也可以自定义资源类来实现自己资源文件的封装.
接下来看看spring对它的封装,代码如下:
''''''
/**
* 资源类的抽象类
*/
public interface Resource extends InputStreamSource {
/**资源是否存在*/
boolean exists();
/**资源是否可读,这里首先需要判断该资源是否存在*/
default boolean isReadable() {
return exists();
}
/**描述的是资源的一个句柄,默认是没有打开的*/
default boolean isOpen() {
return false;
}
/**资源是否是一个file*/
default boolean isFile() {
return false;
}
/**返回资源URL的句柄*/
URI getURI() throws IOException;
/**返回资源file的句柄*/
File getFile() throws IOException;
/**返回资源文件的大小,这里是字节大小*/
long contentLength() throws IOException;
/**
* Determine the last-modified timestamp for this resource.
* @throws IOException if the resource cannot be resolved
* (in the file system or as some other known physical resource type)
*/
/**资源的修改时间*/
long lastModified() throws IOException;
/**
* Create a resource relative to this resource.
* @param relativePath the relative path (relative to this resource)
* @return the resource handle for the relative resource
* @throws IOException if the relative resource cannot be determined
*/
/**创建一个相对于此资源文件路径的资源*/
Resource createRelative(String relativePath) throws IOException;
@Nullable
/**获取资源文件的name*/
String getFilename();
/**返回此资源的描述内容*/
String getDescription();
}
上述是spring是如何封装资源的方法,我们可以看到Resource继承了InputStreamSource类,我们再来看看这个类到底是干了什么,代码如下:
public interface InputStreamSource {
/**获取资源的内容*/
InputStream getInputStream() throws IOException;
}
- 该接口就一个方法,获取资源文件的内容,看完了spring是如何封装资源文件的.接下看spring是加载资源文件的
- 接着上面的我们来看,当我们new ClassPathResource()时,都干了什么,代码如下:
public ClassPathResource(String path) {
this(path, (ClassLoader) null);
}
- 该方法是ClassPathResource类中方法,初始化一个ClassPathResoure类
- 其中path为我们定义xml文件的绝对路径
- 这里调用了内部的初始化的方法,只是需要多传了一个ClassLoader参数,代码如下:
/**
*
* @param path 资源的绝对路径
* @param classLoader 当前类的加载器,允许为null
*/
public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
//路径转化,将Windows中的\\简化为\
String pathToUse = StringUtils.cleanPath(path);
//从/开始截取路径
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
//初始化,
this.path = pathToUse;
//获取默认的加载器
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}
- 上述两个方法是ClassPathResource.java中的初始化方法.
- 首先来看一下ClassPathResource的自定义属性,代码如下:
private final String path;//当前我们配置文件的路径
@Nullable
private ClassLoader classLoader;//默认为null
@Nullable
private Class<?> clazz;//默认为null
我们可以看到它自己属性,一目了然,我们来看看是如何获取当前的加载器的过程,代码如下:
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
// getClassLoader() returning null indicates the bootstrap ClassLoader
try {
cl = ClassLoader.getSystemClassLoader();
}
catch (Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
}
}
}
return cl;
}
- 代码简单明了,获取当前线程的上下文加载器,没拿到的话
- 通过当前类的class来获取加载器,如果没拿到
- 通过顶级加载器来获取
总结:
- 当我们new ClassPathResource()时,首先是我们配置文件的定位.
- 然后进行内部相应的抽象成一个Resource .
- 以及初始化一个默认的资源加载器
篇幅太长,下篇继续.......
转载于:https://www.jianshu.com/p/0bf4510519c7