Spring 源码第一篇开整!配置文件是怎么加载的?( 二 )

代码倒不难,我来稍微解释下:

  1. InputStreamSource 类只提供了一个 getInputStream 方法,该方法返回一个 InputStream,也就是说,InputStreamSource 会将传入的 File 等资源,封装成一个 InputStream 再重新返回 。
  2. Resource 接口实现了 InputStreamSource 接口,并且封装了 Spring 内部可能会用到的底层资源,如 File、URL 以及 classpath 等 。
  3. exists 方法用来判断资源是否存在 。
  4. isReadable 方法用来判断资源是否可读 。
  5. isOpen 方法用来判断资源是否打开 。
  6. isFile 方法用来判断资源是否是一个文件 。
  7. getURL/getURI/getFile/readableChannel 分别表示获取资源对应的 URL/URI/File 以及将资源转为 ReadableByteChannel 通道 。
  8. contentLength 表示获取资源的大小 。
  9. lastModified 表示获取资源的最后修改时间 。
  10. createRelative 表示根据当前资源创建一个相对资源 。
  11. getFilename 表示获取文件名 。
  12. getDescription 表示在资源出错时,详细打印出出错的文件 。
当我们加载不同资源时,对应了 Resource 的不同实现类,来看下 Resource 的继承关系:
Spring 源码第一篇开整!配置文件是怎么加载的?

文章插图
 
可以看到,针对不同类型的数据源,都有各自的实现,我们这里来重点看下 ClassPathResource 的实现方式 。
ClassPathResource 源码比较长,我这里挑一些关键部分来和大家分享:
public class ClassPathResource extends AbstractFileResolvingResource { private final String path; @Nullable private ClassLoader classLoader; @Nullable private Class<?> clazz; 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; } public final String getPath() {  return this.path; } @Nullable public final ClassLoader getClassLoader() {  return (this.clazz != null ? this.clazz.getClassLoader() : this.classLoader); } @Override public boolean exists() {  return (resolveURL() != null); } @Nullable protected URL resolveURL() {  if (this.clazz != null) {   return this.clazz.getResource(this.path);  }  else if (this.classLoader != null) {   return this.classLoader.getResource(this.path);  }  else {   return ClassLoader.getSystemResource(this.path);  } } @Override public InputStream getInputStream() throws IOException {  InputStream is;  if (this.clazz != null) {   is = this.clazz.getResourceAsStream(this.path);  }  else if (this.classLoader != null) {   is = this.classLoader.getResourceAsStream(this.path);  }  else {   is = ClassLoader.getSystemResourceAsStream(this.path);  }  if (is == null) {   throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");  }  return is; } @Override public URL getURL() throws IOException {  URL url = resolveURL();  if (url == null) {   throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist");  }  return url; } @Override public Resource createRelative(String relativePath) {  String pathToUse = StringUtils.ApplyRelativePath(this.path, relativePath);  return (this.clazz != null ? new ClassPathResource(pathToUse, this.clazz) :    new ClassPathResource(pathToUse, this.classLoader)); } @Override @Nullable public String getFilename() {  return StringUtils.getFilename(this.path); } @Override public String getDescription() {  StringBuilder builder = new StringBuilder("class path resource [");  String pathToUse = this.path;  if (this.clazz != null && !pathToUse.startsWith("/")) {   builder.append(ClassUtils.classPackageAsResourcePath(this.clazz));   builder.append('/');  }  if (pathToUse.startsWith("/")) {   pathToUse = pathToUse.substring(1);  }  builder.append(pathToUse);  builder.append(']');  return builder.toString(); }}


推荐阅读