Spring如何加载xml文件
文章目录
- 前言
- 一、统一资源:Resource
- 1.整体结构
- 二、ResourceLoader
- 1.整体结构
- 2.方法getResource
- 3.ResourcePatternResolver
- 三、spring如何定位资源?
- 1.分析入口
- 2.流程跟踪
- 总结
前言
我们大体上知道spring可以通过读取xml配置文件,创建创建对象,然后放到ioc容器中,哪在代码层面是如何实现?这个过程用了什么的样的设计思想?本篇主要主要从整体结构上阅读spring的源码,看是如何进行资源定位?
一、统一资源:Resource
org.springframework.core.io.Resource
为 Spring 框架所有资源的抽象和访问接口,它继承 org.springframework.core.io.InputStreamSource
接口。作为所有资源的统一抽象,Resource
定义了一些通用的方法,由子类 AbstractResource
提供统一的默认实现。
public interface Resource extends InputStreamSource {boolean exists();default boolean isReadable() {return exists();}default boolean isOpen() {return false;}default boolean isFile() {return false;}URL getURL() throws IOException;URI getURI() throws IOException;File getFile() throws IOException;default ReadableByteChannel readableChannel() throws IOException {return Channels.newChannel(getInputStream());}long contentLength() throws IOException;long lastModified() throws IOException;Resource createRelative(String relativePath) throws IOException;@NullableString getFilename();String getDescription();}
public interface InputStreamSource {InputStream getInputStream() throws IOException;
}
1.整体结构
Resource
根据资源的不同类型提供不同的具体实现,如下:
FileSystemResource
:对 java.io.File
类型资源的封装,只要是跟 File 打交道的,基本上与 FileSystemResource
也可以打交道。支持文件和 URL 的形式。
ByteArrayResource
:对字节数组提供的数据的封装。
UrlResource
:对 java.net.URL类型资源的封装。内部委派 URL 进行具体的资源操作。
ClassPathResource
:classpath 类型资源的实现。使用给定的 ClassLoader
或者给定的 Class 来加载资源。
其中AbstractResource
提供了大部分的实现。如果我们想要实现自定义的 Resource 只需要继承AbstractResource
抽象类,然后根据当前的具体资源特性覆盖相应的方法即可。
Spring 将资源的定义和资源的加载区分开,Resource
定义了统一的资源,资源的加载则由 ResourceLoader
来统一定义。
二、ResourceLoader
ResourceLoader
定义资源加载器,主要应用于根据给定的资源文件地址,返回对应的 Resource
。
public interface ResourceLoader {/** Pseudo URL prefix for loading from the class path: "classpath:". */String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;Resource getResource(String location);@NullableClassLoader getClassLoader();
}
#getResource(String location)
方法,根据所提供资源的路径 location 返回 Resource
实例。
该方法支持以下模式的资源加载:
URL位置资源,如 "file:C:/test.dat"
。
ClassPath位置资源,如 "classpath:test.dat
。
相对路径资源,如 "WEB-INF/test.dat"
,此时返回的Resource
实例,根据实现不同而不同。
该方法的主要实现是在其子类 DefaultResourceLoader
中实现
1.整体结构
2.方法getResource
org.springframework.core.io.DefaultResourceLoader
是 ResourceLoader
的默认实现。其getResource(String location)
如下
// DefaultResourceLoader.java@Override
public Resource getResource(String location) {Assert.notNull(location, "Location must not be null");// 首先,通过 ProtocolResolver 来加载资源for (ProtocolResolver protocolResolver : this.protocolResolvers) {Resource resource = protocolResolver.resolve(location, this);if (resource != null) {return resource;}}// 其次,以 / 开头,返回 ClassPathContextResource 类型的资源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());// 然后,根据是否为文件 URL ,是则返回 FileUrlResource 类型的资源,否则返回 UrlResource 类型的资源} else {try {// Try to parse the location as a URL...URL url = new URL(location);return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));} catch (MalformedURLException ex) {// 最后,返回 ClassPathContextResource 类型的资源// No URL -> resolve as resource path.return getResourceByPath(location);}}
}
3.ResourcePatternResolver
另外需要关注的是:
ResourceLoader
的 Resource getResource(String location)
方法,每次只能根据 location
返回一个 Resource
。其子类org.springframework.core.io.support.ResourcePatternResolver
在它的基础上进行了扩展,支持根据指定的资源路径匹配模式每次返回多个 Resource
实例,其定义如下:
public interface ResourcePatternResolver extends ResourceLoader {String CLASSPATH_ALL_URL_PREFIX = "classpath*:";Resource[] getResources(String locationPattern) throws IOException;}
org.springframework.core.io.support.PathMatchingResourcePatternResolver
,为 ResourcePatternResolver
最常用的子类,它除了支持 ResourceLoader
和 ResourcePatternResolver
新增的 classpath*:
前缀外,还支持 Ant 风格的路径匹配模式(类似于 “**/*.xml”)。
/*** 内置的 ResourceLoader 资源定位器*/
private final ResourceLoader resourceLoader;
/*** Ant 路径匹配器*/
private PathMatcher pathMatcher = new AntPathMatcher();public PathMatchingResourcePatternResolver() {this.resourceLoader = new DefaultResourceLoader();
}public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {Assert.notNull(resourceLoader, "ResourceLoader must not be null");this.resourceLoader = resourceLoader;
}public PathMatchingResourcePatternResolver(@Nullable ClassLoader classLoader) {this.resourceLoader = new DefaultResourceLoader(classLoader);
}
@Overridepublic Resource getResource(String location) {return getResourceLoader().getResource(location);}
ResourceLoader
在实例化的时候,可以指定一个 ResourceLoader
,并在getResource
方法中使用了该ResourceLoader
,如果不提供,则默认使用DefaultResourceLoader
。
PathMatchingResourcePatternResolver
最大的不同是提供了getResources
方法的实现。
@Override
public Resource[] getResources(String locationPattern) throws IOException {Assert.notNull(locationPattern, "Location pattern must not be null");// 以 "classpath*:" 开头if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {// 路径包含通配符// a class path resource (multiple resources for same name possible)if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {// a class path resource patternreturn findPathMatchingResources(locationPattern);// 路径不包含通配符} else {// all class path resources with the given namereturn findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));}// 不以 "classpath*:" 开头} else {// Generally only look for a pattern after a prefix here, // 通常只在这里的前缀后面查找模式// and on Tomcat only after the "*/" separator for its "war:" protocol. 而在 Tomcat 上只有在 “*/ ”分隔符之后才为其 “war:” 协议int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :locationPattern.indexOf(':') + 1);// 路径包含通配符if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {// a file patternreturn findPathMatchingResources(locationPattern);// 路径不包含通配符} else {// a single resource with the given namereturn new Resource[] {getResourceLoader().getResource(locationPattern)};}}
}
这里不展开对getResources
方法的分析。我们重点关注,spring是如何使用Resource
跟ResourceLoader
的
三、spring如何定位资源?
1.分析入口
创建一个测试主函数
public static void main(String[] args) {ApplicationContext context =new ClassPathXmlApplicationContext("classpath*:application.xml");UserService userService = context.getBean(UserService.class);System.out.println(userService);// 这句将输出: hello worldSystem.out.println(userService.getName());}
2.流程跟踪
这里先暂且忽略其他流程,一致找到加载xml文件的地方
上面的流程可通过端点跟踪或者是ClassPathXmlApplicationContext
类的继承结构找到对应的实现。
这里重要的一个地方是beanDefinitionReader.setResourceLoader(this);
,也就是说AbstractXmlApplicationContext
及其子类也属于ResourceLoader
。继续跟踪
这里到AbstractBeanDefinitionReader#loadBeanDefinitions
方法后,就是我们的目的地了,下面来分析该方法
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {// 获取加载器 也就是上面的beanDefinitionReader.setResourceLoader(this);ResourceLoader resourceLoader = getResourceLoader();if (resourceLoader == null) {throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");}if (resourceLoader instanceof ResourcePatternResolver) {// Resource pattern matching available.try {Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);int count = loadBeanDefinitions(resources);if (actualResources != null) {Collections.addAll(actualResources, resources);}if (logger.isTraceEnabled()) {logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");}return count;}catch (IOException ex) {throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex);}}else {// Can only load single resources by absolute URL.Resource resource = resourceLoader.getResource(location);int count = loadBeanDefinitions(resource);if (actualResources != null) {actualResources.add(resource);}if (logger.isTraceEnabled()) {logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");}return count;}}
在分析上面方法之前,先来看一张类关系图
从上面结构图中可以看出,我们创建的ClassPathXmlApplicationContext
也实现了ResourceLoader
,并且判断resourceLoader instanceof ResourcePatternResolver
为true.
ClassPathXmlApplicationContext
的getResource
最终又委托给了ResourcePatternResolver
进行实现
ResourcePatternResolver
再根据不同的location
匹配返回不同的Resource
对象
总结
- 不同的资源路径(location),对应不同的
Resource
对象 - 根据location,由
ResourceLoader
进行加载,返回不同的Resouce
对象 ResourcePatternResolver
对ResourceLoader
进行了增强,可以处理多个locationClassPathXmlApplicationContext
也实现了ResourceLoader
,但并不直接获取Resource
,而是委托给了ResourcePatternResolver
进行处理
到这里,还有一点没有弄清楚,ClassPathXmlApplicationContext
为什么要实现ResourceLoader
呢?
Spring如何加载xml文件相关推荐
- Spring如何加载XSD文件(org.xml.sax.SAXParseException: Failed to read schema document错误的解决方法)...
本文原文连接: http://blog.csdn.net/bluishglc/article/details/7596118 ,转载请注明出处! 有时候你会发现过去一直启动正常的系统,某天启动时会报出 ...
- org.xml.sax.SAXParseException: Failed to read schema document错误的完美解决方法 以及 Spring如何加载XSD文件
有时候你会发现过去一直启动正常的系统,某天启动时会报出形如下面的错误: org.xml.sax.SAXParseException: schema_reference.4: Failed to rea ...
- Spring加载xml文件错误异常:Offending resource: class path resource [spring-context.xml];
很少写单纯的java工程,在运行的时候,加载xml文件的时候报错,在此记录错误信息,备自己以后查阅,错误信息如下: Java HotSpot(TM) 64-Bit Server VM warning: ...
- Spring中加载xml配置文件的六种方式
Spring中加载xml配置文件的六种方式 博客分类: Spring&EJB XMLSpringWebBeanBlog 因为目前正在从事一个项目,项目中一个需求就是所有的功能都是插件的形式装 ...
- Spring如何加载XSD文件
http://blog.csdn.net/bluishglc/article/details/7596118 本文原文连接: http://blog.csdn.net/bluishglc/articl ...
- spring boot 加载静态文件
spring boot 加载静态文件 @Slf4j @Configuration public class WebMvcConfig extends WebMvcConfigurationSuppor ...
- 解决dom4j加载xml文件性能慢的问题
解决dom4j加载xml文件性能慢的问题 参考文章: (1)解决dom4j加载xml文件性能慢的问题 (2)https://www.cnblogs.com/wulm/p/9863104.html 备忘 ...
- android xml 加载错误提示,加载uixml文件失败 打开wps时显示“加载XML文件失败1
打开wps时显示"加载XML文件失败." 打开wps时显示"加载XML文件失败1 关闭所有打开的Word文档: 开始 → 运行 → 粘贴上面复制的命令 → 确定. 在打开 ...
- [转载]spring+mybatis加载属性文件设置数据源失败原因及解决方案 - 泡在网上的日子
spring+mybatis加载属性文件设置数据源失败原因及解决方案 - 泡在网上的日子 http://www.jcodecraeer.com/a/chengxusheji/java/2013/062 ...
- IDEA 加载xml文件失败,解决方案
问题 在IDEA中,第在src/main路径下添加了xml,使用如下代码加载xml文件时: String path = JsoupDemo.class.getClassLoader().getReso ...
最新文章
- 酷狗音乐QQ显示(VC源代码)
- dhcp 续约review报文_Linux的私房菜 DHCP
- OSI七层模型的作用
- 大数据之_亿级分布式日志管理ELK_工作笔记001_ELK认识介绍
- 华为 “VRRP” 多备份组
- python数据分析与应用-Python数据分析与应用 PDF 内部全资料版
- 排队论模型(八):Matlab 生成随机数、排队模型的计算机模拟
- 太极软件qn的代码_多版本QQ内置qn、qx模块
- 大英博物馆天猫开店,本王的宝贝都要被你们玩坏啦!
- 计算机网络面试常见题
- 【Java语言】交换两个数的数值
- 【机器学习】深入浅出经典贝叶斯统计
- 智能家居有必要HomeKit吗?
- linux win10自带浏览器,win10系统下如何安装opera浏览器
- 解码元宇宙,深度剖析元宇宙空间+数字人+数字孪生
- google开源服务器apprtc的搭建
- 随机实现“泰坦”与“宙斯”之间的模拟交战。说明:本题以希腊神话中宙斯和泰坦间的交战为背景
- 站群管理软件-通过SEO拓展业务并吸引潜在客户
- 智能时代,电话销售如何打造高效的智能化解决方案?
- JAVA窗体程序调用图片、音频、字体资源