【小家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的获取了~~~


相关文章
|
2月前
|
XML Java 数据格式
探索Spring之利剑:ApplicationContext接口
本文深入介绍了Spring框架中的核心接口ApplicationContext,解释了其作为应用容器的功能,包括事件发布、国际化支持等,并通过基于XML和注解的配置示例展示了如何使用ApplicationContext管理Bean实例。
112 6
|
3月前
|
监控 Java 应用服务中间件
Spring Boot整合Tomcat底层源码分析
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置和起步依赖等特性,大大简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是其与Tomcat的整合。
85 1
|
22天前
|
监控 Java 应用服务中间件
SpringBoot是如何简化Spring开发的,以及SpringBoot的特性以及源码分析
Spring Boot 通过简化配置、自动配置和嵌入式服务器等特性,大大简化了 Spring 应用的开发过程。它通过提供一系列 `starter` 依赖和开箱即用的默认配置,使开发者能够更专注于业务逻辑而非繁琐的配置。Spring Boot 的自动配置机制和强大的 Actuator 功能进一步提升了开发效率和应用的可维护性。通过对其源码的分析,可以更深入地理解其内部工作机制,从而更好地利用其特性进行开发。
42 6
|
2月前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
3月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
55 1
|
3月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
53 1
|
3月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
48 0
|
Java Spring
通过Spring Resource接口获取资源(6)
通过Spring Resource接口获取资源
1143 0
|
Java Spring 数据格式
Spring Resource接口获取资源
1.1.1. Resource简介  在Spring内部实现机制,针对于资源文件(配置的xml文件)有一个统一的接口Resource。   1.1.1.1. 接口定义的方法 1.exists():判断资源文件是否存在。
1624 0
|
Java Spring 数据格式
通过Spring Resource接口获取资源
通过Spring Resource接口获取资源 目录 1       Resource简介 2       通过ResourceLoader获取资源 3       在bean中获取Resource的方式   1       Resource简介        在Spring内部,针对于资源文件有一个统一的接口Resource表示。
938 0