在Spring容器中,有一个基础的抽象概念:资源(Resource),其主要是对文件或类路径等资源的抽象,当对Spring容器进行初始化等操作时,会将配置文件以Resource参数对象传入给Spring容器,内部再通过ResourceLoader加载该资源,本文将比较探讨下Spring对资源的处理细节。
-
Resource定义
在Spring中,资源通过Resource接口作了基础定义:
可以看到Resource继承自InputStreamSource,该接口定义了getInputStream()方法,用于获取资源对应的输入流对象。Spring中也提供了多种Resource实现,这可以从Resource继承树中看出:
其中有我们比较熟悉的ClasspathResource(类路径资源,Main应用程序常用),FileSystemResource(文件系统资源)等,所有Resource的实现均继承自AbstractResource,其实现了一些基本功能:
AbstractResource似乎并没有作太多事情,只提过一些默认实现。
-
Resource实现
-
ByteArrayResource:
ByteArrayResource通过内部封装一个byte[],比较简单地实现了Resource。
-
FileSystemResource:
FileSystemResource内部包装了一个File对象,并实现了WritableResource接口,可以获取到资源的输出流进行写操作等。
-
AbstractFileResolvingResource:
AbstractFileResolvingResource作为UrlResource,ClassPathResource等的基类,主要负责将这类资源转换为File对象:
-
ClassPathResource:
ClassPathResource作为较常用的资源类型,比如在初始化Spring容器时,我们通常会传入一个classpath:开头的资源,SpringSpring容器则根据这个构建一个ClassPathResource对象。
-
ResourceLoader定义
既然有了Resource,则还需要一个能加载Resource的组件,因为我们并不希望每次都都通过new的方式去构建一个Resource,这个组件叫ResourceLoader,其定义了加载资源的策略:
同样Spring已经提供一些ResourceLoader的实现:
其中DefaultResourceLoader和PathMatchingResourcePatternResolver是比较常见的,也可看到AbstractApplicationContext继承自DefaultResourceLoader,继承自AbstractApplicationContext的IoC容器就已经具备加载资源的能力。
-
ResourceLoader实现
-
DefaultResourceLoader
DefaultResourceLoader作为最普遍的资源加载器,可看其实现也相对简单:
-
ResourcePatternResolver
ResourcePatternResolver是对ResourceLoader的扩展,具备匹配资源模式(如Ant-Style)的功能,即将某一模式的资源location转为Resource数据,并增加了classpath*:前缀的资源解析:
-
PathMatchingResourcePatternResolver
PathMatchingResourcePatternResolver作为ResourcePatternResolver的实现,被很多地方使用,如ClassPathXmlApplicationContext容器初始化AbstractBeanDefinitionReader时,就是使用PathMatchingResourcePatternResolver作为资源加载器:
PathMatchingResourcePatternResolver如何实现资源加载:
PathMatchingResourcePatternResolver中包装了一个比较重要的路径匹配器AntPathMatcher完成了路径匹配工作,匹配规范为Ant-Style,主要匹配工作可参考AntPathMatcher.doMatch方法,具体的使用可以参照下其测试用例:
以上则是一些有关Spring中资源管理的小部分细节,平时还比较常用的地方就是在Spring配置文件中使用import标签:
import时,Spring IoC容器会进一步加载resource资源,但classpath:one-context.xml会加载类路径中的查询到的第一个one-context.xml,而classpath*:two-context.xml还会加载类路径中多个jar中的two-context.xml,本质则是因为classpath:开头的资源,最终调用ClassLoader.getResource()方法,classpath*:开头的资源,最终调用ClassLoader.getResources()方法,可以将组件通过在jar包中提供一个配置文件(名字应规范,避免冲突),外部只需通过classpath:前缀import就能使用该组件。