【小家Spring】资源访问利器---Spring提供的Resource接口以及它的常用子类源码分析(下)

简介: 【小家Spring】资源访问利器---Spring提供的Resource接口以及它的常用子类源码分析(下)

DescriptiveResource


这个类更简单,仅仅一个不可变的描述字符串的包装


// @since 1.2.6
public class DescriptiveResource extends AbstractResource {
  @Override
  public InputStream getInputStream() throws IOException {
    throw new FileNotFoundException(
        getDescription() + " cannot be opened because it does not point to a readable resource");
  }
}


这个类实际只是对资源描述的定义,既不是可读,实际文件也是不存在的,其他Resource接口中的方法也并未实现。当一个方法需要你传递一个资源对象,但又不会在方法中真正读取该对象的时候,如果没有合适的资源对象作为参数,就创建一个 DescriptiveResource 资源做参数。比如ConfigurationClass就有使用~~~


另外BeanDefinitionResource和DescriptiveResource有点像。但它持有的是一个BeanDefinition,也不能对它进行读、写。一般也是占位用的

AbstractFileResolvingResource


它复写了AbstractResource大多数方法,是一个比较重要的分支。有不少非常好用的实现类


// @since 3.0
public abstract class AbstractFileResolvingResource extends AbstractResource {
}


image.png


UrlResource:通过URL地址获取资源

可以从网络里获取资源


    public static void main(String[] args) throws IOException {
        UrlResource resource = new UrlResource("http://www.springframework.org/schema/beans/spring-beans.xsd");
        if (resource.exists()) {
            File file = resource.getFile();
            System.out.println(file); //报错 java.io.FileNotFoundException: URL [xxx] cannot be resolved to absolute file path because it
            dumpStream(resource); //输出这个.xsd文件的所有的内容...
        }
    }

FileUrlResource


//@since 5.0.2 显然它出现得很晚。 并且还实现了WritableResource接口
public class FileUrlResource extends UrlResource implements WritableResource {
  @Nullable
  private volatile File file;
  public FileUrlResource(URL url) {
    super(url);
  }
  // 注意:若使用此构造函数,此处使用的是file协议  而UrlResource采用的是http协议,此处需注意
  // 若想http,请用上面构造。自己构造一个URL对象吧
  public FileUrlResource(String location) throws MalformedURLException {
    super(ResourceUtils.URL_PROTOCOL_FILE, location);
  }
  @Override
  public File getFile() throws IOException {
    File file = this.file;
    if (file != null) {
      return file;
    }
    file = super.getFile();
    this.file = file;
    return file;
  }
  @Override
  public boolean isWritable() {
    try {
      URL url = getURL();
      if (ResourceUtils.isFileURL(url)) {
        // Proceed with file system resolution
        File file = getFile();
        return (file.canWrite() && !file.isDirectory());
      }
      else {
        return true;
      }
    }
    catch (IOException ex) {
      return false;
    }
  }
  @Override
  public OutputStream getOutputStream() throws IOException {
    return Files.newOutputStream(getFile().toPath());
  }
  @Override
  public WritableByteChannel writableChannel() throws IOException {
    return FileChannel.open(getFile().toPath(), StandardOpenOption.WRITE);
  }
}


它提供了我们访问网络资源能像访问本地文件一样的能力~~~


    public static void main(String[] args) throws IOException {
        //FileUrlResource resource = new FileUrlResource("http://www.springframework.org/schema/beans/spring-beans.xsd");
        FileUrlResource resource = new FileUrlResource(new URL("http://www.springframework.org/schema/beans/spring-beans.xsd"));
        if (resource.exists()) {
            dumpStream(resource); //输出这个.xsd文件的所有的内容...
        }
    }


ClassPathResource:通过类路径获取资源文件


听这名字就知道,它是直接去读取类路径下的资源文件的。


其实它的底层都是依赖于我们上面说得clazz.getResourceAsStream或者classLoader.getResourceAsStream。掌握了上面之后,这个其实就非常简单了

public class ClassPathResource extends AbstractFileResolvingResource {
  private final String path;'
  @Nullable
  private ClassLoader classLoader;
  @Nullable
  private Class<?> clazz; // 它还可以自己指定clazz
  @Nullable
  public final ClassLoader getClassLoader() {
    return (this.clazz != null ? this.clazz.getClassLoader() : this.classLoader);
  }
  @Override
  public boolean exists() {
    return (resolveURL() != null);
  }
  // 这是它最重要的一个方法,依赖于JDK的实现嘛
  @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;
  }
  // 非常简单 直接解析path即可
  @Override
  @Nullable
  public String getFilename() {
    return StringUtils.getFilename(this.path);
  }
}


Demo:


    public static void main(String[] args) {
        //ClassPathResource resource = new ClassPathResource("spring.properties");
        // 如果是要获取指定类所在包下的文件,建议指定class
        ClassPathResource resource = new ClassPathResource("demo.properties",Main.class);
        if (resource.exists()) {
            dumpStream(resource); //name=fangshixiang  或者 demo=value
        }
    }

ServletContextResource:获取ServletContext环境下的资源



这个在web包里面。org.springframework.web.context.support


为访问Web容器上下文中的资源而设计的类,负责以相对于Web应用程序根目录的路径加载资源,它支持以流和URL的方式访问,在WAR解包的情况下,也可以通过File的方式访问,还可以直接从JAR包中访问资源


public class ServletContextResource extends AbstractFileResolvingResource implements ContextResource {
  // 持有servletContext的引用
  private final ServletContext servletContext;
  private final String path;
  // 只提供这一个构造函数,来构造一个资源
  public ServletContextResource(ServletContext servletContext, String path) {
    // check ServletContext
    Assert.notNull(servletContext, "Cannot resolve ServletContextResource without ServletContext");
    this.servletContext = servletContext;
    // check path
    Assert.notNull(path, "Path is required");
    String pathToUse = StringUtils.cleanPath(path);
    if (!pathToUse.startsWith("/")) {
      pathToUse = "/" + pathToUse;
    }
    this.path = pathToUse;
  }
  // 我们发现,它底层都是依赖于servletContext.getResource  getResourceAsStream这些方法去找到资源的
  @Override
  public boolean isFile() {
    try {
      URL url = this.servletContext.getResource(this.path);
      if (url != null && ResourceUtils.isFileURL(url)) {
        return true;
      }
      else {
        return (this.servletContext.getRealPath(this.path) != null);
      }
    }
    catch (MalformedURLException ex) {
      return false;
    }
  }
  @Override
  public InputStream getInputStream() throws IOException {
    InputStream is = this.servletContext.getResourceAsStream(this.path);
    if (is == null) {
      throw new FileNotFoundException("Could not open " + getDescription());
    }
    return is;
  }
  // 这个有点意思。如果URL就是File类型。就ok
  // 如果不是file类型,就根据绝对路径 new一个出来
  @Override
  public File getFile() throws IOException {
    URL url = this.servletContext.getResource(this.path);
    if (url != null && ResourceUtils.isFileURL(url)) {
      // Proceed with file system resolution...
      return super.getFile();
    }
    else {
      String realPath = WebUtils.getRealPath(this.servletContext, this.path);
      return new File(realPath);
    }
  }
}


总结


Spring内部,针对于资源文件有一个统一的接口Resource表示。

因为我们现在绝大部分应用都构建在Spring的基础上,因此它提供的这些便捷的获取资源的工具,我们也是可以使用的。而不用去使用源生JDK的获取了~~~


相关文章
|
22天前
|
Java API 微服务
【Spring Boot系列】通过OpenAPI规范构建微服务服务接口
【4月更文挑战第5天】通过OpenAPI接口构建Spring Boot服务RestAPI接口
|
5天前
|
Java Spring
spring boot访问接口报500
spring boot访问接口报500
12 2
|
16天前
|
Java 数据库连接 数据库
spring+mybatis_编写一个简单的增删改查接口
spring+mybatis_编写一个简单的增删改查接口
16 2
|
29天前
|
算法 NoSQL Java
限流艺术:Spring Boot接口限流的实用指南
限流艺术:Spring Boot接口限流的实用指南
64 0
限流艺术:Spring Boot接口限流的实用指南
|
Java Spring
通过Spring Resource接口获取资源(6)
通过Spring Resource接口获取资源
1031 0
|
Java Spring 数据格式
Spring Resource接口获取资源
1.1.1. Resource简介  在Spring内部实现机制,针对于资源文件(配置的xml文件)有一个统一的接口Resource。   1.1.1.1. 接口定义的方法 1.exists():判断资源文件是否存在。
1532 0
|
Java Spring 数据格式
通过Spring Resource接口获取资源
通过Spring Resource接口获取资源 目录 1       Resource简介 2       通过ResourceLoader获取资源 3       在bean中获取Resource的方式   1       Resource简介        在Spring内部,针对于资源文件有一个统一的接口Resource表示。
871 0
|
2月前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
53 0
|
2月前
|
缓存 安全 Java
Spring Boot 面试题及答案整理,最新面试题
Spring Boot 面试题及答案整理,最新面试题
137 0
|
1月前
|
存储 JSON Java
SpringBoot集成AOP实现每个接口请求参数和返回参数并记录每个接口请求时间
SpringBoot集成AOP实现每个接口请求参数和返回参数并记录每个接口请求时间
43 2