Spring IOC: 统一资源加载策略

「这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战」。

统一资源 Resource

Resource是Spring框架所有资源的抽象和访问接口,定义了一些通用方法,通过子类AbstractResource提供统一实现

子类结构

image.png

  • FileSystemResource:对File类型资源进行封装

  • ByteArrayResource : 对字节数组提供的数据进行封装。

  • UrlResource:对URL类型资源进行封装

  • ClassPathResource:对class path类型资源的实现

  • InputStreamResource : 将给定的InputStream作为一种资源的Resource实现类

AbstractResource

Resource接口默认实现,实现了Resource接口的大部分公共实现

统一资源定位 ResourceLoader

Spring将资源定义和资源加载区分开,Resource定义了统一的资源,资源的加载由ResourceLoader来统一定义。

ResourceLoader是资源加载的统一抽象,具体资源加载由子类实现,可以将ResourceLoader称为统一资源定位器,主要应用于根据给定资源文件,返回对应的Resource.


public interface ResourceLoader {

String CLASSPATH_URL_PREFIX = "classpath:";

Resource getResource(String var1);

@Nullable

ClassLoader getClassLoader();

}

复制代码
  1. getResource

根据所提供资源路径location返回Resource实例,该方法支持url,classpath,相对路径等资源

  1. getClassLoader

返回classLoader实例。

子类结构

image.png

DefaultResourceLoader

与AbstractResource相似,是ResourceLoader的默认实现

构造函数

它接收ClassLoader作为构造函数的参数,不带参数的构造函数,使用默认的ClassLoader

getSource方法

getSource方法是ResourceLoader最核心的方法,DefaultResourceLoader对该方法提供了核心的实现。

这个方法首先会根据提供的location返回相应的Resource.

  • 首先通过 ProtocolResolver 来加载资源,成功返回 Resource.

  • 其次会判断llocation的具体类型返回相应的Resource资源。

ProtocolResolver

用户自定义协议资源解决策略,它允许用户自定义资源加载协议,而不需要基础ResourceLoader的子类。

ProtocolResolver 接口,仅有一个方法 Resource resolve(String location, ResourceLoader resourceLoader)。

资源加载示例


public class ResourceTest {

public static void main(String[] args) {

ResourceLoader resourceLoader = new DefaultResourceLoader();

Resource fileResource1 = resourceLoader.getResource("E:/k.txt");

System.out.println("fileResource1 is FileSystemResource:" + (fileResource1 instanceof FileSystemResource));

Resource fileResource2 = resourceLoader.getResource("/Users/chenming673/Documents/spark.txt");

System.out.println("fileResource2 is ClassPathResource:" + (fileResource2 instanceof ClassPathResource));

Resource urlResource1 = resourceLoader.getResource("file:/Users/chenming673/Documents/spark.txt");

System.out.println("urlResource1 is UrlResource:" + (urlResource1 instanceof UrlResource));

Resource urlResource2 = resourceLoader.getResource("http://www.baidu.com");

System.out.println("urlResource1 is urlResource:" + (urlResource2 instanceof UrlResource));

}

}

---- 运行结果--

fileResource1 is FileSystemResource:false

fileResource2 is ClassPathResource:true

urlResource1 is UrlResource:true

urlResource1 is urlResource:true

复制代码

对于fileResource1,之所以返回false,因为它是ClassPathResource类型

我们知道 "E:/k.txt"" 地址,其实在该方法中没有相应的资源类型,那么它就会在抛出 MalformedURLException 异常时,通过 DefaultResourceLoader#getResourceByPath(...) 方法,构造一个 ClassPathResource 类型的资源。

FileSystemResourceLoader

继承了DefaultResourceLoader ,且覆写了 getResourceByPath(String) 方法

用来加载文件系统资源,并返回FileSystemResource类型.

FileSystemContextResource ,为 FileSystemResourceLoader 的内部类,它继承 FileSystemResource 类,实现 ContextResource 接口

ClassRelativeResourceLoader

与FileSystemResourceLoader类似,重写了getResourceByPath()方法,不过它可以根据给定的class所在包或者所在包子包加载资源。

ResourcePatternResolver

它支持根据指定的资源路径匹配模式每次返回多个Resource实例。

总结

  • Spring 提供了 Resource 和 ResourceLoader 来统一抽象整个资源及其定位。使得资源与资源的定位有了一个更加清晰的界限,并且提供了合适的 Default 类,使得自定义实现更加方便和清晰。

  • AbstractResource 为 Resource 的默认抽象实现,它对 Resource 接口做了一个统一的实现,子类继承该类后只需要覆盖相应的方法即可,同时对于自定义的 Resource 我们也是继承该类。

  • DefaultResourceLoader 同样也是 ResourceLoader 的默认实现,在自定 ResourceLoader 的时候我们除了可以继承该类外还可以实现 ProtocolResolver 接口来实现自定资源加载协议。

  • DefaultResourceLoader 每次只能返回单一的资源,所以 Spring 针对这个提供了另外一个接口 ResourcePatternResolver ,该接口提供了根据指定的 locationPattern 返回多个资源的策略。其子类 PathMatchingResourcePatternResolver 是一个集大成者的 ResourceLoader ,因为它即实现了 Resource getResource(String location) 方法,也实现了 Resource[] getResources(String locationPattern)方法。

猜你喜欢

转载自juejin.im/post/7035267547804991519