Spring官网阅读(十二)ApplicationContext详解(中)(1)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Spring官网阅读(十二)ApplicationContext详解(中)(1)

1、Spring的资源(Resource)


首先需要说明的是,Spring并没有让ApplicationContext直接继承Resource接口,就像ApplicationContext接口也没有直接继承Environment接口一样。这应该也不难理解,采用这种组合的方式会让我们的类更加的轻量,也起到了解耦的作用。ApplicationContext跟Resource相关的接口的继承关系如下

image.png

不管是ResourceLoader还是ResourcePatternResolver其实都是为了获取Resource对象,不过ResourcePatternResolver在ResourceLoader的基础上扩展了一个获取多个Resource的方法,我们在后文会介绍。


接口简介


Resouce接口继承了 InputStreamSource.

public interface InputStreamSource {
    // 每次调用都将返回一个当前资源对应的java.io. InputStream字节流
    InputStream getInputStream() throws IOException;
}
public interface Resource extends InputStreamSource {  
  // 用于判断对应的资源是否真的存在
  boolean exists();
  // 用于判断对应资源的内容是否可读。需要注意的是当其结果为true的时候,其内容未必真的可读,但如果返回false,则其内容必定不可读
  default boolean isReadable() {
    return exists();
  }
  // 用于判断当前资源是否代表一个已打开的输入流,如果结果为true,则表示当前资源的输入流不可多次读取,而且在读取以后需要对它进行关闭,以防止内存泄露。该方法主要针对于实现类InputStreamResource,实现类中只有它的返回结果为true,其他都为false。
  default boolean isOpen() {
    return false;
  }
    // 当前资源是否是一个文件
  default boolean isFile() {
    return false;
  }
  //当前资源对应的URL。如果当前资源不能解析为一个URL则会抛出异常
  URL getURL() throws IOException;
  //当前资源对应的URI。如果当前资源不能解析为一个URI则会抛出异常
  URI getURI() throws IOException;
  // 返回当前资源对应的File。如果当前资源不能以绝对路径解析为一个File则会抛出异常。
  File getFile() throws IOException;
  // 返回一个ReadableByteChannel
  default ReadableByteChannel readableChannel() throws IOException {
    return Channels.newChannel(getInputStream());
  }
  //  返回资源的长度
  long contentLength() throws IOException;
  // 最后修改时间
  long lastModified() throws IOException;
  // 根据当前资源以及相对当前资源的路径创建一个新的资源,比如当前Resource代表文件资源“d:/abc/a.java”,则createRelative(“xyz.txt”)将返回表文件资源“d:/abc/xyz.txt”
  Resource createRelative(String relativePath) throws IOException;
  // 返回文件一个文件名称,通常来说会返回该资源路径的最后一段
  @Nullable
  String getFilename();
  // 返回描述信息
  String getDescription();
}

UML类图


微信图片_20221112201852.png


因为实现了Resource接口的类很多,并且一些类我们也不常用到或者很简单,所以上图中省略了一些不重要的分支,接下来我们就一个个分析。


抽象基类AbstractResource


实现了Resource接口,是大多数Resource的实现类的基类,提供了很多通用的方法。

比如exists方法会检查是否一个文件或者输入流能够被打开。isOpen永远返回false。”getURL()” 和”getFile()”方法会抛出异常。toString将会返回描述信息。


FileSystemResource


基于java的文件系统封装而成的一个资源对象。


AbstractFileResolvingResource


将URL解析成文件引用,既会处理协议为:“file“的URL,也会处理JBoss的”vfs“协议。然后相应的解析成对应的文件系统引用。


ByteArrayResource


根据一个给定的字节数组构建的一个资源。同时给出一个对应的输入流


BeanDefinitionResource


只是对BeanDefinition进行的一次描述性的封装


InputStreamResource


是针对于输入流封装的资源,它的构建需要一个输入流。 对于“getInputStream ”操作将直接返回该字节流,因此只能读取一次该字节流,即“isOpen”永远返回true。


UrlResource


UrlResource代表URL资源,用于简化URL资源访问。

UrlResource一般支持如下资源访问:

-http:通过标准的http协议访问web资源,如new UrlResource(“http://地址”);

-ftp:通过ftp协议访问资源,如new UrlResource(“ftp://地址”);

-file:通过file协议访问本地文件系统资源,如new UrlResource(“file:d:/test.txt”);


ClassPathResource


JDK获取资源有两种方式


1.使用Class对象的getResource(String path)获取资源URL,getResourceAsStream(String path)获取资源流。 参数既可以是当前class文件相对路径(以文件夹或文件开头),也可以是当前class文件的绝对路径(以“/”开头,相对于当前classpath根目录)

2.使用ClassLoader对象的getResource(String path)获取资源URL,getResourceAsStream(String path)获取资源流。参数只能是绝对路径,但不以“/”开头

ClassPathResource代表classpath路径的资源,将使用给定的Class或ClassLoader进行加载classpath资源。 “isOpen”永远返回false,表示可多次读取资源。


ServletContextResource


是针对于ServletContext封装的资源,用于访问ServletContext环境下的资源。ServletContextResource持有一个ServletContext的引用,其底层是通过ServletContext的getResource()方法和getResourceAsStream()方法来获取资源的。


ResourceLoader


接口简介


ResourceLoader接口被设计用来从指定的位置加载一个Resource,其接口定义如下

public interface ResourceLoader {
   // classpath:
  String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
    // 核心方法,从指定位置加载一个Resource
    // 1.支持权限的的URL格式,如:file:C:/test.dat
    // 2.支持classpath的格式,如:classpath:test.dat
    // 3.支持文件相对路径,如:WEB-INF/test.dat
  Resource getResource(String location);
    // 返回用于加载该资源的ClassLoader
  @Nullable
  ClassLoader getClassLoader();
}

UML类图


image.png

对于一些不是很必要的类我都省略了,其实核心的类我们只需要关注DefaultResourceLoader就可以了,因为其余子类(除了GenericApplicationContext)都是直接继承了DefaultResourceLoader的getResource方法。代码如下:

  @Override
  public Resource getResource(String location) {
    Assert.notNull(location, "Location must not be null");
        // 正常来说protocolResolvers集合是空的,除非我们调用了它的addProtocolResolver方法添加了自定义协议处理器,调用addProtocolResolver方法所添加的协议处理器会覆盖原有的处理逻辑
    for (ProtocolResolver protocolResolver : this.protocolResolvers) {
      Resource resource = protocolResolver.resolve(location, this);
      if (resource != null) {
        return resource;
      }
    }
        // 如果是以“/”开头,直接返回一个classpathResource
    if (location.startsWith("/")) {
      return getResourceByPath(location);
    }
        // 如果是形如:classpath:test.dat也直接返回一个ClassPathResource
    else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
      return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
    }
    else {
      try {
        // 否则将其解析为一个URL
        URL url = new URL(location);
                // 如果是一个文件,直接返回一个FileUrlResource,否则返回一个普通的UrlResource
        return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
      }
      catch (MalformedURLException ex) {
        // 如果URL转换失败,还是作为一个普通的ClassPathResource
        return getResourceByPath(location);
      }
    }
  }

资源路径


ant-style

类似下面这种含有通配符的路径

/WEB-INF/*-context.xml
com/mycompany/**/applicationContext.xml
file:C:/some/path/*-context.xml
classpath:com/mycompany/**/applicationContext.xml
相关文章
|
6月前
|
Java 应用服务中间件 Spring
Spring5源码(50)-SpringMVC源码阅读环境搭建
Spring5源码(50)-SpringMVC源码阅读环境搭建
78 0
|
5月前
|
存储 Java 程序员
Spring 注册BeanPostProcessor 源码阅读
Spring 注册BeanPostProcessor 源码阅读
|
6月前
|
Java 测试技术 数据库连接
【Spring源码解读!底层原理高级进阶】【下】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨
【Spring源码解读!底层原理高级进阶】【下】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨
|
5月前
|
存储 Java C++
理解SpringIOC和DI第一课(Spring的特点),IOC对应五大注解,ApplicationContext vs BeanFactory
理解SpringIOC和DI第一课(Spring的特点),IOC对应五大注解,ApplicationContext vs BeanFactory
|
6月前
|
Java Spring 容器
Spring底层原理之 BeanFactory 与 ApplicationContext
Spring底层原理之 BeanFactory 与 ApplicationContext
64 3
|
6月前
|
XML Java 开发者
【Spring源码解读 底层原理高级进阶】【上】探寻Spring内部:BeanFactory和ApplicationContext实现原理讲解
【Spring源码解读 底层原理高级进阶】【上】探寻Spring内部:BeanFactory和ApplicationContext实现原理讲解
|
Java Spring
Spring源码系列(补充):详解ApplicationContext
本文介绍了Spring框架中ApplicationContext的几个核心概念,包括MessageSource、ResourcePatternResolver、获取运行时环境、ApplicationEventPublisher和OrderComparator。对于每个概念,文章都提供了具体的用法示例和注意事项。如果您正在学习或使用Spring框架,本文将为您提供有价值的参考。
Spring源码系列(补充):详解ApplicationContext
|
6月前
|
XML Java 数据格式
Spring5源码(26)-ApplicationContext容器refresh过程简析
Spring5源码(26)-ApplicationContext容器refresh过程简析
58 0
|
6月前
|
Java C++ Spring
深入Spring原理-1.BeanFactory与ApplicationContext的区别
深入Spring原理-1.BeanFactory与ApplicationContext的区别
94 0
|
11月前
|
XML Java 数据格式
[读书笔记]Spring中BeanFactory和ApplicationContext的联系和区别
[读书笔记]Spring中BeanFactory和ApplicationContext的联系和区别
52 0