从上图可以看到,Resource 根据资源的不同类型提供不同的具体实现,如下:
- FileSystemResource:对
java.io.File类型资源的封装,只要是跟 File 打交道的,基本上与 FileSystemResource 也可以打交道。支持文件和 URL 的形式,实现 WritableResource 接口,且从 Spring Framework 5.0 开始,FileSystemResource 使用NIO.2 API进行读/写交互 - ByteArrayResource:对字节数组提供的数据的封装。如果通过 InputStream 形式访问该类型的资源,该实现会根据字节数组的数据构造一个相应的 ByteArrayInputStream。
- UrlResource:对
java.net.URL类型资源的封装。内部委派 URL 进行具体的资源操作。 - ClassPathResource:class path 类型资源的实现。使用给定的 ClassLoader 或者给定的 Class 来加载资源。
- InputStreamResource:将给定的 InputStream 作为一种资源的 Resource 的实现类。
AbstractResource 为 Resource 接口的默认实现,它实现了 Resource 接口的大部分的公共实现,作为 Resource 接口中的重中之重,其定义如下:
public abstract class AbstractResource implements Resource { /** * 判断文件是否存在,若判断过程产生异常(因为会调用SecurityManager来判断),就关闭对应的流 */ @Override public boolean exists() { try { return getFile().exists(); } catch (IOException ex) { // Fall back to stream existence: can we open the stream? try { InputStream is = getInputStream(); is.close(); return true; } catch (Throwable isEx) { return false; } } } /** * 直接返回true,表示可读 */ @Override public boolean isReadable() { return true; } /** * 直接返回 false,表示未被打开 */ @Override public boolean isOpen() { return false; } /** * 直接返回false,表示不为 File */ @Override public boolean isFile() { return false; } /** * 抛出 FileNotFoundException 异常,交给子类实现 */ @Override public URL getURL() throws IOException { throw new FileNotFoundException(getDescription() + " cannot be resolved to URL"); } /** * 基于 getURL() 返回的 URL 构建 URI */ @Override public URI getURI() throws IOException { URL url = getURL(); try { return ResourceUtils.toURI(url); } catch (URISyntaxException ex) { throw new NestedIOException("Invalid URI [" + url + "]", ex); } } /** * 抛出 FileNotFoundException 异常,交给子类实现 */ @Override public File getFile() throws IOException { throw new FileNotFoundException(getDescription() + " cannot be resolved to absolute file path"); } /** * 根据 getInputStream() 的返回结果构建 ReadableByteChannel */ @Override public ReadableByteChannel readableChannel() throws IOException { return Channels.newChannel(getInputStream()); } /** * 获取资源的长度 * * 这个资源内容长度实际就是资源的字节长度,通过全部读取一遍来判断 */ @Override public long contentLength() throws IOException { InputStream is = getInputStream(); try {
