Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Spring入门:Resource

Spring入门:Resource

作者头像
WEBJ2EE
发布于 2019-08-14 12:25:22
发布于 2019-08-14 12:25:22
90200
代码可运行
举报
文章被收录于专栏:WebJ2EEWebJ2EE
运行总次数:0
代码可运行

1. Resource ?

Spring 把所有能记录信息的载体,如各种类型的文件、二进制流等都称为资源,对 Spring 开发者来说,最常用的资源就是 Spring 配置文件(通常是一份 XML 格式的文件)。 Spring 资源访问剖析和策略模式应用(李刚)

2. 为什么 Spring 要搞 Resource ?

一方面:增强 Java 原生的资源访问能力

Spring 需要与各式各样的资源打交道:

  • Url 资源(网络资源)
  • classpath 资源(类加载路径里的资源)
  • File 资源(文件系统
  • SerlvetContext 资源(相对于 ServletContext 路径里的资源)
  • 自定义资源(开发通过 ByteArray、InputStream 自由构造)

然而,用 Java 的 File、URL 访问这些底层资源的步骤过于繁琐。Spring 为资源访问提供了一个 Resource 接口,该接口提供了更强的资源访问能力。

图:Resource 接口

另一方面:对资源进行统一抽象,屏蔽资源访问细节

Resource 接口就是策略模式的典型应用,应用只和 Resource 接口耦合,并不知道底层采用何种资源访问策略,这样应用可以在不同的资源访问策略之间自由切换。

Spring 为 Resource 接口提供了如下实现类:

  • UrlResource:用于访问网络资源
  • ClassPathResource:用于访问类加载路径中资源
  • FileSystemResource:用于访问文件系统中资源
  • ServletContextResource:用于 ServletContext 路径中的资源
  • InputStreamResource:用于自定义资源来源
  • ByteArrayResource:用于自定义资源来源

3. Resource 应用示例

Resource 不仅可在 Spring 的项目中使用,也可直接作为资源访问的工具类使用。意思是说:即使不使用 Spring 框架,也可以使用 Resource 作为工具类,用来代替 URL。当然,使用 Resource 接口会让代码与 Spring 的接口耦合在一起,但这种耦合只是部分工具集的耦合,不会造成太大的代码污染。

示例1:FileSystemResource

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import org.apache.commons.io.IOUtils;import org.springframework.core.io.FileSystemResource;
import java.io.IOException;import java.util.Date;
public class ResourceDemo {    public static void main(String[] args) throws IOException {        FileSystemResource fsr = new FileSystemResource("E:/springdemo/src/main/resources/webj2ee.txt");        System.out.println("exists: "+fsr.exists());        System.out.println("readable: "+fsr.isReadable());        System.out.println("writable: "+fsr.isWritable());        System.out.println("path: "+fsr.getPath());        System.out.println("fileName: "+fsr.getFilename());        System.out.println("lastModified: "+new Date(fsr.lastModified()));        System.out.println("description: "+fsr.getDescription());        System.out.println("content: "+IOUtils.toString(fsr.getInputStream(), "UTF-8"));    }}

示例2:ClassPathResource

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import org.apache.commons.io.IOUtils;import org.springframework.core.io.ClassPathResource;
import java.io.IOException;import java.util.Date;
public class ResourceDemo {    public static void main(String[] args) throws IOException {
        ClassPathResource fsr = new ClassPathResource("webj2ee/webj2ee.txt");        System.out.println("exists: "+fsr.exists());        System.out.println("readable: "+fsr.isReadable());        System.out.println("isFile: "+fsr.isFile());        System.out.println("path: "+fsr.getPath());        System.out.println("fileName: "+fsr.getFilename());        System.out.println("lastModified: "+new Date(fsr.lastModified()));        System.out.println("description: "+fsr.getDescription());        System.out.println("content: "+IOUtils.toString(fsr.getInputStream(), "UTF-8"));    }}

示例3:ServletContextResource

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package webj2ee;
import org.apache.commons.io.IOUtils;import org.springframework.web.context.support.ServletContextResource;
import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.Date;
@WebServlet(name = "SCRDemo",urlPatterns = {"/SCRDemo"})public class SCRDemo extends HttpServlet {    @Override    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        ServletContextResource fsr = new ServletContextResource(request.getServletContext(), "webj2ee-servletcontext/webj2ee.txt");        System.out.println("exists: " + fsr.exists());        System.out.println("readable: " + fsr.isReadable());        System.out.println("path: " + fsr.getPath());        System.out.println("URL: "+fsr.getURL());        System.out.println("URI: "+fsr.getURI());        System.out.println("fileName: " + fsr.getFilename());        System.out.println("lastModified: " + new Date(fsr.lastModified()));        System.out.println("description: " + fsr.getDescription());        System.out.println("content: " + IOUtils.toString(fsr.getInputStream(), "UTF-8"));    }}

总结:Spring 提供的各种 Resource 实现类非常实用,避免了直接使用 URL、File 的繁琐、复杂,建议在项目中直接使用。

4. Resource 基本原理

Resource 的各实现类

涉及IO、NIO、JAR、File、Classpath 众多技术细节

留待后续文章详细分析

Resource 总体架构:

InputStreamSource.java 源码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package org.springframework.core.io;
import java.io.IOException;import java.io.InputStream;
/** * Simple interface for objects that are sources for an {@link InputStream}. * * <p>This is the base interface for Spring's more extensive {@link Resource} interface. * * <p>For single-use streams, {@link InputStreamResource} can be used for any * given {@code InputStream}. Spring's {@link ByteArrayResource} or any * file-based {@code Resource} implementation can be used as a concrete * instance, allowing one to read the underlying content stream multiple times. * This makes this interface useful as an abstract content source for mail * attachments, for example. */public interface InputStreamSource {  /**   * Return an {@link InputStream} for the content of an underlying resource.   * <p>It is expected that each call creates a <i>fresh</i> stream.   * <p>This requirement is particularly important when you consider an API such   * as JavaMail, which needs to be able to read the stream multiple times when   * creating mail attachments. For such a use case, it is <i>required</i>   * that each {@code getInputStream()} call returns a fresh stream.   * @return the input stream for the underlying resource (must not be {@code null})   * @throws java.io.FileNotFoundException if the underlying resource doesn't exist   * @throws IOException if the content stream could not be opened   */  InputStream getInputStream() throws IOException;}

Resource.java 源码节选:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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;
/** * Interface for a resource descriptor that abstracts from the actual * type of underlying resource, such as a file or class path resource. * * <p>An InputStream can be opened for every resource if it exists in * physical form, but a URL or File handle can just be returned for * certain resources. The actual behavior is implementation-specific. */public interface Resource extends InputStreamSource {
  /**   * Determine whether this resource actually exists in physical form.   * <p>This method performs a definitive existence check, whereas the   * existence of a {@code Resource} handle only guarantees a valid   * descriptor handle.   */  boolean exists();
  /**   * Indicate whether non-empty contents of this resource can be read via   * {@link #getInputStream()}.   * <p>Will be {@code true} for typical resource descriptors that exist   * since it strictly implies {@link #exists()} semantics as of 5.1.   * Note that actual content reading may still fail when attempted.   * However, a value of {@code false} is a definitive indication   * that the resource content cannot be read.   * @see #getInputStream()   * @see #exists()   */  default boolean isReadable() {    return exists();  }
  /**   * Indicate whether this resource represents a handle with an open stream.   * If {@code true}, the InputStream cannot be read multiple times,   * and must be read and closed to avoid resource leaks.   * <p>Will be {@code false} for typical resource descriptors.   */  default boolean isOpen() {    return false;  }
  /**   * Determine whether this resource represents a file in a file system.   * A value of {@code true} strongly suggests (but does not guarantee)   * that a {@link #getFile()} call will succeed.   * <p>This is conservatively {@code false} by default.   * @since 5.0   * @see #getFile()   */  default boolean isFile() {    return false;  }
  /**   * Return a URL handle for this resource.   * @throws IOException if the resource cannot be resolved as URL,   * i.e. if the resource is not available as descriptor   */  URL getURL() throws IOException;
  /**   * Return a URI handle for this resource.   * @throws IOException if the resource cannot be resolved as URI,   * i.e. if the resource is not available as descriptor   * @since 2.5   */  URI getURI() throws IOException;
  /**   * Return a File handle for this resource.   * @throws java.io.FileNotFoundException if the resource cannot be resolved as   * absolute file path, i.e. if the resource is not available in a file system   * @throws IOException in case of general resolution/reading failures   * @see #getInputStream()   */  File getFile() throws IOException;  /**   * Determine the content length for this resource.   * @throws IOException if the resource cannot be resolved   * (in the file system or as some other known physical resource type)   */  long contentLength() throws IOException;
  /**   * Determine the last-modified timestamp for this resource.   * @throws IOException if the resource cannot be resolved   * (in the file system or as some other known physical resource type)   */  long lastModified() throws IOException;
  /**   * Create a resource relative to this resource.   * @param relativePath the relative path (relative to this resource)   * @return the resource handle for the relative resource   * @throws IOException if the relative resource cannot be determined   */  Resource createRelative(String relativePath) throws IOException;
  /**   * Determine a filename for this resource, i.e. typically the last   * part of the path: for example, "myfile.txt".   * <p>Returns {@code null} if this type of resource does not   * have a filename.   */  @Nullable  String getFilename();
  /**   * Return a description for this resource,   * to be used for error output when working with the resource.   * <p>Implementations are also encouraged to return this value   * from their {@code toString} method.   * @see Object#toString()   */  String getDescription();}

AbstractResource.java 源码节选:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package org.springframework.core.io;
import java.io.File;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStream;import java.net.URI;import java.net.URISyntaxException;import java.net.URL;import java.nio.channels.Channels;import java.nio.channels.ReadableByteChannel;
import org.springframework.core.NestedIOException;import org.springframework.lang.Nullable;import org.springframework.util.ResourceUtils;
/** * Convenience base class for {@link Resource} implementations, * pre-implementing typical behavior. * * <p>The "exists" method will check whether a File or InputStream can * be opened; "isOpen" will always return false; "getURL" and "getFile" * throw an exception; and "toString" will return the description. * * @author Juergen Hoeller * @since 28.12.2003 */public abstract class AbstractResource implements Resource {
  /**   * This implementation checks whether a File can be opened,   * falling back to whether an InputStream can be opened.   * This will cover both directories and content resources.   */  @Override  public boolean exists() {    // Try file existence: can we find the file in the file system?    try {      return getFile().exists();    }    catch (IOException ex) {      // Fall back to stream existence: can we open the stream?      try {        getInputStream().close();        return true;      }      catch (Throwable isEx) {        return false;      }    }  }
  /**   * This implementation always returns {@code true} for a resource   * that {@link #exists() exists} (revised as of 5.1).   */  @Override  public boolean isReadable() {    return exists();  }
  /**   * This implementation always returns {@code false}.   */  @Override  public boolean isOpen() {    return false;  }
  /**   * This implementation always returns {@code false}.   */  @Override  public boolean isFile() {    return false;  }
  /**   * This implementation throws a FileNotFoundException, assuming   * that the resource cannot be resolved to a URL.   */  @Override  public URL getURL() throws IOException {    throw new FileNotFoundException(getDescription() + " cannot be resolved to URL");  }
  /**   * This implementation builds a URI based on the URL returned   * by {@link #getURL()}.   */  @Override  public URI getURI() throws IOException {    URL url = getURL();    try {      return ResourceUtils.toURI(url);    }    catch (URISyntaxException ex) {      throw new NestedIOException("Invalid URI [" + url + "]", ex);    }  }
  /**   * This implementation throws a FileNotFoundException, assuming   * that the resource cannot be resolved to an absolute file path.   */  @Override  public File getFile() throws IOException {    throw new FileNotFoundException(getDescription() + " cannot be resolved to absolute file path");  }
  /**   * This implementation returns {@link Channels#newChannel(InputStream)}   * with the result of {@link #getInputStream()}.   * <p>This is the same as in {@link Resource}'s corresponding default method   * but mirrored here for efficient JVM-level dispatching in a class hierarchy.   */  @Override  public ReadableByteChannel readableChannel() throws IOException {    return Channels.newChannel(getInputStream());  }
  /**   * This implementation reads the entire InputStream to calculate the   * content length. Subclasses will almost always be able to provide   * a more optimal version of this, e.g. checking a File length.   * @see #getInputStream()   */  @Override  public long contentLength() throws IOException {    InputStream is = getInputStream();    try {      long size = 0;      byte[] buf = new byte[256];      int read;      while ((read = is.read(buf)) != -1) {        size += read;      }      return size;    }    finally {      try {        is.close();      }      catch (IOException ex) {      }    }  }
  /**   * This implementation checks the timestamp of the underlying File,   * if available.   * @see #getFileForLastModifiedCheck()   */  @Override  public long lastModified() throws IOException {    File fileToCheck = getFileForLastModifiedCheck();    long lastModified = fileToCheck.lastModified();    if (lastModified == 0L && !fileToCheck.exists()) {      throw new FileNotFoundException(getDescription() +          " cannot be resolved in the file system for checking its last-modified timestamp");    }    return lastModified;  }
  /**   * Determine the File to use for timestamp checking.   * <p>The default implementation delegates to {@link #getFile()}.   * @return the File to use for timestamp checking (never {@code null})   * @throws FileNotFoundException if the resource cannot be resolved as   * an absolute file path, i.e. is not available in a file system   * @throws IOException in case of general resolution/reading failures   */  protected File getFileForLastModifiedCheck() throws IOException {    return getFile();  }
  /**   * This implementation throws a FileNotFoundException, assuming   * that relative resources cannot be created for this resource.   */  @Override  public Resource createRelative(String relativePath) throws IOException {    throw new FileNotFoundException("Cannot create a relative resource for " + getDescription());  }
  /**   * This implementation always returns {@code null},   * assuming that this resource type does not have a filename.   */  @Override  @Nullable  public String getFilename() {    return null;  }

  /**   * This implementation compares description strings.   * @see #getDescription()   */  @Override  public boolean equals(Object other) {    return (this == other || (other instanceof Resource &&        ((Resource) other).getDescription().equals(getDescription())));  }
  /**   * This implementation returns the description's hash code.   * @see #getDescription()   */  @Override  public int hashCode() {    return getDescription().hashCode();  }
  /**   * This implementation returns the description of this resource.   * @see #getDescription()   */  @Override  public String toString() {    return getDescription();  }}

参考:

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#resources https://www.ibm.com/developerworks/cn/java/j-lo-spring-resource/index.html https://tools.ietf.org/html/rfc3986

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 WebJ2EE 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【小家Spring】资源访问利器---Spring提供的Resource接口以及它的常用子类源码分析
资源是一个抽象的概念,什么是资源?我们已知Spring中有很多xml配置文件,同时还可能自建各种properties资源文件,还有可能进行网络交互,收发各种文件、二进制流等。
YourBatman
2019/09/03
1.6K0
【小家Spring】资源访问利器---Spring提供的Resource接口以及它的常用子类源码分析
【Spring】资源操作管理:Resource、ResourceLoader、ResourceLoaderAware;
Spring 的 Resource 接口位于 org.springframework.core.io 中。 旨在成为一个更强大的接口,用于抽象对低级资源的访问。以下显示了Resource接口定义的方法
.29.
2023/10/17
5840
【Spring】资源操作管理:Resource、ResourceLoader、ResourceLoaderAware;
Spring 资源文件处理
Java中,不同来源的资源抽象成URL,通过注册不同的handler(URLStreamHandler)来处理不同来源的资源的读取逻辑。一般handler的类型使用不同的前缀(协议,protocal)来识别,如:“file:”、“http:“、”jar:”等。
WindWant
2020/09/11
6300
【死磕 Spring】----- IOC 之 Spring 统一资源加载策略
在学 Java SE 的时候我们学习了一个标准类 java.net.URL,该类在 Java SE 中的定位为统一资源定位器(Uniform Resource Locator),但是我们知道它的实现基本只限于网络形式发布的资源的查找和定位。然而,实际上资源的定义比较广泛,除了网络形式的资源,还有以二进制形式存在的、以文件形式存在的、以字节流形式存在的等等。而且它可以存在于任何场所,比如网络、文件系统、应用程序中。所以 java.net.URL 的局限性迫使 Spring 必须实现自己的资源加载策略,该资源加载策略需要满足如下要求:
用户1655470
2018/09/30
7720
【死磕 Spring】----- IOC 之 Spring 统一资源加载策略
spring 之资源操作:Resources
在 Java 编程中,java.net.URL 类常用于进行资源操作。然而,这个类在访问某些底层资源时存在局限性。例如,它不能直接从类路径中获取资源,或者在 Web 项目中无法方便地访问相对于服务器上下文的资源。此外,java.net.URL 在功能方面也有所欠缺,比如无法检测某个资源是否存在。
叫我阿杰好了
2024/01/03
2070
spring 之资源操作:Resources
Java-利用Spring提供的Resource/ResourceLoader接口操作资源文件
JDK提供的访问资源的类(如java.net.URL、File等)并不能很好地满足各种底层资源的访问需求,比如缺少从类路径或者Web容器上下文中获取资源的操作类。
小小工匠
2021/08/16
1.7K0
Spring 源码第一篇开整!配置文件是怎么加载的?
松哥给最近连载的 Spring Security 系列也录制了视频教程,感兴趣的小伙伴请戳这里->Spring Boot+Vue+微人事视频教程(Spring Boot 第十章就是 Spring Security)。
江南一点雨
2020/06/17
4860
Spring6reRescourse资源的使用及Spring6国际化
Java的标准java.net.URL类和各种URL前缀的标准处理程序无法满足所有对low-level资源的访问,比如:没有标准化的 URL 实现可用于访问需要从类路径或相对于 ServletContext 获取的资源。并且缺少某些Spring所需要的功能,例如检测某资源是否存在等。而Spring的Resource声明了访问low-level资源的能力。
小小程序员
2023/03/27
4920
Spring6reRescourse资源的使用及Spring6国际化
Spring Resources资源操作
Java的标准java.net.URL类和各种URL前缀的标准处理程序无法满足所有对low-level资源的访问,比如:没有标准化的 URL 实现可用于访问需要从类路径或相对于 ServletContext 获取的资源。并且缺少某些Spring所需要的功能,例如检测某资源是否存在等。而Spring的Resource声明了访问low-level资源的能力。
鱼找水需要时间
2023/06/15
2970
Spring Resources资源操作
Resource 体系介绍
在使用spring作为容器进行项目开发中会有很多的配置文件,这些配置文件都是通过Spring的Resource接口来实现加载,但是,Resource对于所有低级资源的访问都不够充分。例如,没有标准化的URL实现可用于访问需要从类路径或相对于ServletContext获取的资源。虽然可以为专用的URL前缀注册新的处理程序(类似于http :)这样的前缀的现有处理程序,但这通常非常复杂,并且URL接口仍然缺少一些理想的功能,例如检查存在的方法被指向的资源。
cxuan
2019/06/17
1.3K0
Spring读源码系列01---Spring核心类及关联性介绍
阅读本系列之前,建议先从本专栏的两个不同视角学习spring的系列作为入门学习点(这两个系列会持续更新),先大体理解spring的架构设计与精髓,然后再来阅读本系列,深入源码分析,而不再纸上谈兵
大忽悠爱学习
2022/05/10
3700
Spring读源码系列01---Spring核心类及关联性介绍
Spring5源码解析_IOC之容器的基本实现
Bean是Spring最核心的东西,Spring就像是一个大水桶,而Bean就是水桶中的水,水桶脱离了水就没有了什么用处,我们简单看一下Bean的定义,代码如下:
@派大星
2023/06/28
2090
Spring5源码解析_IOC之容器的基本实现
Spring源码学习笔记(1)——容器的基本实现
上述代码完成了Spring容器的基本功能,看似简单,但是背后却封装了复杂的逻辑。下面我们结合源码看下Spring到底做了哪些处理。
张申傲
2020/09/03
2950
IOC XMLBeanDefinitionReader
Spring的配置文件读取是通过ClassPathResource进行封装的,如new ClassPathResource ("beanFactoryTest.xml")。
程序员酷森
2020/10/19
5540
IOC XMLBeanDefinitionReader
Spring复杂的BeanFactory继承体系该如何理解?---中下
作为Spring提供的较之BeanFactory更为先进的IoC容器实现,ApplicationContext除了拥有BeanFactory支持的所有功能之外,还进一步扩展了基本容器的功能,包括BeanFactoryPostProcessor、BeanPostProcessor以及其他特殊类型bean的自动识别、容器启动后bean实例的自动初始化、国际化的信息支持、容器内事件发布等。真是“青出于蓝而胜于蓝”啊!
大忽悠爱学习
2022/05/10
4020
Spring复杂的BeanFactory继承体系该如何理解?---中下
Java 文件 IO 操作
InputstreamReader 用于将一个字节流中的字节解码成字符 OutputstreamWriter 用于将写入的字符编码成字节后写入一个字节流
Michael阿明
2021/09/06
6690
SpringBoot项目构建成jar运行,如何正确读取resource里的文件
度娘检索出来的文章也基本上告诉你,这样是没有问题的。But,使用mvn package构建成jar文件,运行后报异常如下:
MavenTalker
2019/07/19
12.3K0
手撸Spring框架,设计与实现资源加载器,从Spring.xml解析和注册Bean对象
接,是能接的,接几次也行,哪怕就一个类一片的 if...else 也可以!但接完成什么样可就不一定了,会不会出事故也不是能控制住的。
小傅哥
2021/06/10
5340
手撸Spring框架,设计与实现资源加载器,从Spring.xml解析和注册Bean对象
《Spring 手撸专栏》第 6 章:气吞山河,设计与实现资源加载器,从Spring.xml解析和注册Bean对象
接,是能接的,接几次也行,哪怕就一个类一片的 if...else 也可以!但接完成什么样可就不一定了,会不会出事故也不是能控制住的。
小傅哥
2021/06/25
4390
《Spring 手撸专栏》第 6 章:气吞山河,设计与实现资源加载器,从Spring.xml解析和注册Bean对象
Spring框架源码分析(IoC):Resource、ResourceLoader和容器之间的关系
Resource接口定义了资源常见的操作,抽象出了一些通用方法,再由不同的实现类去自定义。直接上Resource源码:
星如月勿忘初心
2020/08/01
1.3K0
Spring框架源码分析(IoC):Resource、ResourceLoader和容器之间的关系
推荐阅读
相关推荐
【小家Spring】资源访问利器---Spring提供的Resource接口以及它的常用子类源码分析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验