基本概念

ResourceLoader 接口,在 Spring 中用于加载资源,通过它可以获取一个 Resouce 对象。


内部构造

首先来看它的接口定义:

public interface ResourceLoader {

    // 从 classpath 加载资源时的前缀
String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX; // 关键-> 取得 Resource 对象,即获取资源
Resource getResource(String location); ClassLoader getClassLoader();
}

再来看它的继承关系,如下所示:

  • DefaultResourceLoader : 作为 ResourceLoader 接口的直接实现类,该类实现了基本的资源加载功能,可以实现对单个资源的加载。

  • ResourcePatternResolver :该接口继承了 ResourceLoader,定义了加载多个资源的方法, 可以实现对多个资源的加载。


DefaultResourceLoader

上面介绍过该类通过实现 ResourceLoader 接口实现了加载单个资源的功能。它的子类通过继承它来实现具体的资源访问策略。下面来探究下该类如何加载单个资源:

public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null"); // ① 是否以"/" 开头
if (location.startsWith("/")) {
return getResourceByPath(location);
}
// ② 是否以"classpath:" 开头,若是则表示该资源类型为 ClassPathResource
else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
else {
try {
// ③若都不是,则当成 UrlResource 来处理
URL url = new URL(location);
return new UrlResource(url);
}catch (MalformedURLException ex) {
// 若不是 UrlResource,则仍当作 ① 情况来处理
return getResourceByPath(location);
}
}
}

观察代码,发现在拿到资源的路径 loaction 后,会根据 location 的形式分成三种情况来处理:

  • 以 “/” 开头:默认调用类中的 getResourceByPath 方法处理。它的子类通过重写该方法实现不同形式的资源的访问。

  • 以 “classpath:” 开头:当成 ClassPathResource 资源对待。

  • 其他情况: 当成 UrlResource 资源对待,如果访问资源抛出异常,则调用 getResourceByPath 来完成资源的访问。


ResourcePatternResolver

该接口继承自 ResourceLoader 接口,在其基础上增加了同时对多个资源的访问。首先来看它的接口定义:

public interface ResourcePatternResolver extends ResourceLoader {

    String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

    // 例如使用 ant 风格的路径,匹配路径下的多个资源
Resource[] getResources(String locationPattern) throws IOException;
}

1.PathMatchingResourcePatternResolver

该类是 ResourcePatternResolver 接口的直接实现类,它是基于模式匹配的,默认使用AntPathMatcher 进行路径匹配,它除了支持 ResourceLoader 支持的前缀外,还额外支持 “classpath*” ,下面来探究下该类是如何实现对多个资源的访问。

public Resource[] getResources(String locationPattern) throws IOException {

    Assert.notNull(locationPattern, "Location pattern must not be null");

    // 是否以 "classpath*:" 开头
if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) { // 通过 getPathMatcher 方法取得 PathMatcher ,默认只有 AntPathMatcher 一个实现类
// 通过 isPattern 方法判断 "classpath*:" 之后的路径是否包含 "*" 或 "?"
if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) { // 关键 -> 找到所有匹配路径(ant 风格)的资源
return findPathMatchingResources(locationPattern); }else {
// 关键 -> 通过类加载器查找
return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
}
}else { int prefixEnd = locationPattern.indexOf(":") + 1; // 判断资源路径 ":" 之后的部分是否包含 "*" 或 "?"
if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
return findPathMatchingResources(locationPattern);
}else {
// 若不存在表示是单个资源,则通过从构造函数传入的 ResourceLoader 取得
return new Resource[] {getResourceLoader().getResource(locationPattern)};
}
}
}

观察代码:

  • 该方法首先会去判断资源路径是否是类路径下的资源(以 “classpath*:” 开头),然后再去判断路径是否允许存在多个匹配的资源(路径中包含 “*” 或 “?”)。

  • 只要资源路径允许多个匹配的资源,就会通过 findPathMatchingResources 方法寻找所有的匹配资源;

  • 若资源路径只存在单个匹配,则通过类加载器寻找类路径下的资源(findAllClassPathResources) ,其他资源则通过 ResourceLoader 的 getResource 方法获取。


2.ApplicationContext

通过上面的继承关系图可知,该接口继承了 ResourcePatternResolver 接口,说明它也集成了对对单个或多个资源的访问功能。

当 Spring 需要进行资源访问时,实际上并不需要直接使用 Resource 实现类,而是调用 getResource 方法来获取资源。

当通过 ApplicationContext 实例获取 Resource 实例时,它将会负责选择具体的 Resource 的实现类。代码如下:

//通过 ApplicationContext访问资源
Resource res = ctx.getResource("some/resource/path/myTemplate.txt);

从上面代码中无法确定 Spring 将哪个实现类来访问指定资源,Spring 将采用和 ApplicationContext 相同的策略来访问资源。也就是说:如果 ApplicationContext 是 FileSystemXmlApplicationContext,res 就是 FileSystemResource 实例;如果 ApplicationContext 是 ClassPathXmlApplicationContext,res 就是 ClassPathResource 实例;如果 ApplicationContext 是 XmlWebApplicationContext,res 是 ServletContextResource 实例。

也就是说 ApplicationContext 将会确定具体的资源访问策略,从而将应用程序和具体的资源访问策略分离开来,这就体现了策略模式的优势。


参考

06.Spring 资源加载 - ResourceLoader的更多相关文章

  1. Spring资源加载器抽象和缺省实现 -- ResourceLoader + DefaultResourceLoader(摘)

    概述 对于每一个底层资源,比如文件系统中的一个文件,classpath上的一个文件,或者一个以URL形式表示的网络资源,Spring 统一使用 Resource 接口进行了建模抽象,相应地,对于这些资 ...

  2. spring资源加载结构解析

    1.spring中资源加载使用resources的原因? 在java将不同资源抽象成url,然后通过注册不同的hander来处理不同读取逻辑,一般hander使用协议的前缀来命名,如http,jar, ...

  3. spring 资源加载使用说明

    Spring 提供了一个强大加载资源的机制,不但能够通过“classpath:”.“file:” 等资源地址前缀识别不同的资源类型,还支持Ant 风格带通配符的资源地址. 首先,我们来了解一下Spri ...

  4. 05.Spring 资源加载 - Resource

    基本概念 Spring 把所有能记录信息的载体,如各种类型的文件.二进制流等都称为资源. 对 Spring 开发者来说,最常用的资源就是 Spring 配置文件(通常是一份 XML 格式的文件). S ...

  5. Spring资源加载基础ClassLoader

    1 ClassLoader工作机制 1.1 ClassLoader作用 寻找类字节码文件并构造出类在JVM内部表示的组件.负责运行时查找和装入Class字节码文件 1.2 装载步骤 1.2.1 装载 ...

  6. Spring 资源加载

    pom.xml ``` org.springframework spring-core 4.3.14.RELEASE org.springframework spring-beans 4.3.16.R ...

  7. 【死磕 Spring】----- IOC 之 Spring 统一资源加载策略

    原文出自:http://cmsblogs.com 在学 Java SE 的时候我们学习了一个标准类 java.net.URL,该类在 Java SE 中的定位为统一资源定位器(Uniform Reso ...

  8. spring资源访问接口和资源加载接口

    spring 资源访问接口 JDK提供的资源访问类,如java.net.URL.File等,不能很好地满足各种资源的访问需求,比如缺少从类路径或者Web容器的上下文中获取资源的操作类. 鉴于此,spr ...

  9. 简说Spring中的资源加载

    声明: 本文若有 任何纰漏.错误,请不吝指正!谢谢! 问题描述 遇到一个关于资源加载的问题,因此简单的记录一下,对Spring资源加载也做一个记录. 问题起因是使用了@PropertySource来进 ...

随机推荐

  1. node好用的东东

    supervisor 可参考: http://www.cnblogs.com/pigtail/archive/2013/01/08/2851056.html http://www.cnblogs.co ...

  2. sys.argv用法

    argv是在脚本内部使用,旨在接受命令传参 比如,一个脚本argv.py,代码里面有,sys.argv[1],,sys.argv[2],那么运行这个脚本时,必须在后面跟两个参数,用空格隔开,如:pyt ...

  3. poj 1273 Drainage Ditches(最大流,E-K算法)

    一.Description Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clove ...

  4. centos7 查看启动ntp服务命令

    标签(空格分隔): centos7 系统 1. 查看ntp服务命令: [root@node1 ~]# systemctl status ntpd * ntpd.service - Network Ti ...

  5. Sql server 备份及还原

    --最常用的几种备份方法: --数据备份----------------------- --数据库级:完整数据库备份 差异数据库备份 --文件级: 完整文件备份 差异文件备份 --日志备份------ ...

  6. Qt弹出消息对话框

    添加头文件 #include <QMessageBox> if(ui->lineEditXStart->text().isEmpty()) //判断lineedit输入内容是否 ...

  7. spring+jax 出现java.io.Serializable is an interface, and JAXB can't handle interfaces

    spring+jax 出现java.io.Serializable is an interface, and JAXB can't handle interfaces 原因是我的webservice方 ...

  8. Flask05 cookie、类视图、方法视图、自己的404页面

    1 什么是cookie 就是网站存放到你浏览器中的一部分固定内容:当你下次访问我这个网站的时候,你会把之前我存放到你浏览器中的数据带回来给我        你要先登录(用户名.密码) ->   ...

  9. Centos 6.5 hadoop 2.2.0 全分布式安装

    hadoop 2.2.0 cluster setup 环境: 操作系统:Centos 6.5 jdk:jdk1.7.0_51 hadoop版本:2.2.0 hostname    ip master ...

  10. hive2.1.1安装部署

    转至:https://i.cnblogs.com/EditPosts.aspx?opt=1 一.Hive 运行模式 与 Hadoop 类似,Hive 也有 3 种运行模式: 1. 内嵌模式 将元数据保 ...