代码倒不难,我来稍微解释下:
- InputStreamSource 类只提供了一个 getInputStream 方法,该方法返回一个 InputStream,也就是说,InputStreamSource 会将传入的 File 等资源,封装成一个 InputStream 再重新返回 。
- Resource 接口实现了 InputStreamSource 接口,并且封装了 Spring 内部可能会用到的底层资源,如 File、URL 以及 classpath 等 。
- exists 方法用来判断资源是否存在 。
- isReadable 方法用来判断资源是否可读 。
- isOpen 方法用来判断资源是否打开 。
- isFile 方法用来判断资源是否是一个文件 。
- getURL/getURI/getFile/readableChannel 分别表示获取资源对应的 URL/URI/File 以及将资源转为 ReadableByteChannel 通道 。
- contentLength 表示获取资源的大小 。
- lastModified 表示获取资源的最后修改时间 。
- createRelative 表示根据当前资源创建一个相对资源 。
- getFilename 表示获取文件名 。
- getDescription 表示在资源出错时,详细打印出出错的文件 。

文章插图
可以看到,针对不同类型的数据源,都有各自的实现,我们这里来重点看下 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(); }}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 第一次购买羽毛球应该如何挑选
- 茶艺基本知识介绍,中国三峡第四届茶文化艺术节将于15日开幕,茶文化
- 不到五万,搞定你人生第一只钻表
- 第一次去海南旅游应该去哪里
- 茶叶A股第股,14年帕沙古树茶和92年的台地茶对比
- 茶的第功用,白毫茶功用多
- 第一个kafka程序,详谈生产者消费者,顺序消费重复消费问题
- 姜太公为什么自己不封神?
- 淘宝新店流量扶持什么时候开始计算 淘宝新开店铺第几天给流量
- 第二届海峡茶会以,第二届全茶会举办
