在工作之余,开始了啃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。