二、配置文件加载

一、InputStreamSource接口

public interface InputStreamSource {
	InputStream getInputStream() throws IOException;
}

二、Resource接口

public interface Resource extends InputStreamSource {
    //判断资源是否存在
	boolean exists();
    //判断资源是否可读
	default boolean isReadable() {
		return exists();
	}
    //判断资源是否打开
	default boolean isOpen() {
		return false;
	}
    //判断资源是否是一个文件
	default boolean isFile() {
		return false;
	}
    //获取资源对应的URL
	URL getURL() throws IOException;
    //获取资源对应的URI
	URI getURI() throws IOException;
    //获取资源对应的File
	File getFile() throws IOException;
    //将资源转换为ReadableByteChannel
	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();
}

对于不同来源的资源文件都有相应的实现:文件(FileSystemResource)、ClassPath资源(ClassPathResource)、URL资源(UrlResource)、InputStream资源(InputStreamResource)、Byte数组(ByteArrayResource)等
重点看ClassPathResource的实现方式

public ClassPathResource(String path) {
		this(path, (ClassLoader) null);
	}
public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
		Assert.notNull(path, "Path must not be null");
		String pathToUse = StringUtils.cleanPath(path);
		if (pathToUse.startsWith("/")) {
			pathToUse = pathToUse.substring(1);
		}
		this.path = pathToUse;
		this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
	}
public ClassPathResource(String path, @Nullable Class<?> clazz) {
		Assert.notNull(path, "Path must not be null");
		this.path = StringUtils.cleanPath(path);
		this.clazz = clazz;
	}
@Deprecated
protected ClassPathResource(String path, @Nullable ClassLoader classLoader, @Nullable Class<?> clazz) {
		this.path = StringUtils.cleanPath(path);
		this.classLoader = classLoader;
		this.clazz = clazz;
	}

ClassPathResource的构造方法有4个,一个已经过期。另外三个,我们一般调用一个参数的构造函数,即传入文件路径即可,它内部会调用另外一个重载的方法,给classloader赋值(因为后面要通过classloader去读取文件)。

  1. 在 ClassPathResource 初始化的过程中,会先调用 StringUtils.cleanPath 方法对传入的路径进行清理,所谓的路径清理,就是处理路径中的相对地址、Windows 系统下的 \ 变为 / 等。
  2. getPath 方法用来返回文件路径,这是一个相对路径,不包含 classpath。
  3. resolveURL 方法表示返回资源的 URL,返回的时候优先用 Class.getResource 加载,然后才会用 ClassLoader.getResource 加载,关于 Class.getResource 和 ClassLoader.getResource 的区别大概说下,Class.getResource 最终还是会调用 ClassLoader.getResource,只不过 Class.getResource 会先对路径进行处理。
  4. getInputStream 读取资源,并返回 InputStream 对象。
  5. createRelative 方法是根据当前的资源,再创建一个相对资源。

构造出Resource对象之后,还会把Resource对象转换为EncodedResource,这里会对资源进行编码处理,只要体现在getReader方法上,在获取Reader对象时,如果有编码,则给出编码格式:

//org.springframework.core.io.support.EncodedResource
public Reader getReader() throws IOException {
 if (this.charset != null) {
  return new InputStreamReader(this.resource.getInputStream(), this.charset);
 }
 else if (this.encoding != null) {
  return new InputStreamReader(this.resource.getInputStream(), this.encoding);
 }
 else {
  return new InputStreamReader(this.resource.getInputStream());
 }
}

在这之后,就是通过XmlBeanDefinitionReader 去加载Resource了

上一篇:Netty线程模型


下一篇:Netty学习笔记之Java NIO编程