在工作之余,开始了啃Spring源码的艰苦之旅。
Spring 加载资源
首先,我认为Spring框架在启动时,第一步需要加载对应的配置文件.xml
文件。联系之前的java知识,java中的I/O操作可以读取文件。并且在日常的开发工作中,资源文件的加载也是经常用到的。Spring中提供了相关的类来加载,如下:
Resource resource = new ClassPathResource("spring.xml");
InputStream inputStream = resource.getInputStream();
Spring中使用了Resource
来封装底层的资源,同时由于资源的来源不同,Resource
使用了不同的实现类来完成。而Resource
的父类接口 InputStreamSource
只定义了一个getInputStream()
方法,用来获取当前资源的文件流,如下:
public interface InputStreamSource {
InputStream getInputStream() throws IOException;
}
因此可以看到,在Spring中,需要读取文件都会通过getInputStream
来获取对应的I/O流。同时在Resource
中定义了一些方法如下:
package org.springframework.core.io;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import org.springframework.lang.Nullable;
public interface Resource extends InputStreamSource {
/** * 资源文件的存在性 * */
boolean exists();
/** * 资源文件的可读性 */
default boolean isReadable() {
return true;
}
/** * 资源文件是否处于打开状态 */
default boolean isOpen() {
return false;
}
/** * Spring5新增,是否属于文件系统中的文件 */
default boolean isFile() {
return false;
}
/** * 返回资源的URL */
URL getURL() throws IOException;
/** * 返回资源的URI */
URI getURI() throws IOException;
/** *URI,是统一资源标识符,用来唯一的标识一个资源。 *而URL是统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源 */
/** * */
File getFile() throws IOException;
/** *返回读取文件的通道 *Spring5.0 */
default ReadableByteChannel readableChannel() throws IOException {
return Channels.newChannel(getInputStream());
}
/** *文本长度 */
long contentLength() throws IOException;
/** * 上次的修改时间 */
long lastModified() throws IOException;
/** * 基于当前的资源创建一个相对资源 */
Resource createRelative(String relativePath) throws IOException;
@Nullable
String getFilename();
/** * 用于在错误处理中打印信息 */
String getDescription();
}
可以看到在顶层接口Resource
定义了很多通用方法,同时Resource
在Spring的很多实现类如下:
在图中根据类的名字也能够看到,相关的资源来源:文件(FileSystemResource)、Classpath资源(ClassPathResource)、URL资源(UrlResource)、InputStream资源(InputStreamResource)、Byte数组(ByteArrayResource)等等。因此可以了解到,Spring中的配置文件也是通过这样的方式读取的,再把获取到的文件流传递给后面的流程进行解析和注册bean。