基本概念

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. 数据schemaAvro简介

    文章结束给大家来个程序员笑话:[M] 最近在研究Thrift和Avro以及它们的区分,通过各种渠道搜集资料,现整顿出有关Avro的一些资料,方便当前参考. 一.弁言 1. 简介 Avro是Hadoop ...

  2. nodejs 静态文件服务器

    https://cnodejs.org/topic/4f16442ccae1f4aa27001071 http://blog.csdn.net/zhangxin09/article/details/8 ...

  3. NetScaler VPX在Azure上的部署(二)

    本文是Citrix的工程师协助完成.主要是Citrix的VPX的配置. 导入License   进入NetScaler 中点击管理许可   导入后将有提示,请确认重启.   配置Azure HA 由于 ...

  4. 【转】 Pro Android学习笔记(五八):Preferences(2):CheckBoxPreference

    目录(?)[-] CheckBox Preference xml文件 设备的存贮文件 复合preference 在ListPreference的例子中显示的是单选,如果是多选,可采用CheckBoxP ...

  5. JZ2440 启动NFS网络文件系统_初试led驱动

    http://blog.csdn.net/emdfans/article/details/12260969 u-boot ---> q 修改bootargs变量 默认: bootargs=noi ...

  6. .NET生成ICO图标

    using System; using System.Collections.Generic; using System.Web; using System.Drawing; using System ...

  7. 树莓派 Learning 002 装机后必要的操作 --- 09 root用户 密码

    树莓派 装机后必要的操作 - root用户 密码 我的树莓派型号:Raspberry Pi 2 Model B V1.1 装机系统:NOOBS v1.9.2 树莓派使用的Linux是debian系统, ...

  8. get与post方法(吴老师整理)

    Get方式:(用get方式请求时就是调用Servlet中的doGet方法) 1.第一种: 2.第二种:(<a>标签是一种get方式提交) 1.通过GET提交数据,用户名和密码将明文出现在U ...

  9. 用js正则判断输入的两位字符,第一位是数字16进制的,第二位是I、O、Q、U除外的字母(A到Z)

    项目中遇到客户的需求变化,要验证某个数据的正确性,判断输入的两位字符,第一位是数字16进制的,第二位是I.O.Q.U除外的字母(A到Z). 本来对js不熟练,网上参考了一下js正则验证的规则,使用正则 ...

  10. 新一代web框架Koa源码学习

    此文已由作者张佃鹏授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Koa 就是一种简单好用的 Web 框架.它的特点是优雅.简洁.表达力强.自由度高.本身代码只有1000多行 ...