- 前言
- 第一部分 核心实现
- 第 1 章 Spring 整体架构和环境搭建
- 第 2 章 容器的基本实现
- 第 3 章 默认标签的解析
- 第 4 章 自定义标签的解析
- 第 5 章 bean 的加载
- 第 6 章 容器的功能扩展
- 第 7 章 AOP
- 第二部分 企业应用
- 第 8 章 数据库连接 JDBC
- 第 9 章 整合 MyBatis
- 第 10 章 事务
- 第 11 章 SpringMVC
- 第 12 章 远程服务
- 第 13 章 Spring 消息
3.3 import 标签的解析
对于 Spring 配置文件的编写,我想,经历过庞大项目的人,都有那种恐惧的心理,太多的配置文件了。不过,分模块是大多数人能想到的方法,但是,怎么分模块,那就仁者见仁,智者见智了。使用 import 是个好办法,例如我们可以构造这样的 Spring 配置文件:
applicationContext.xml
<?xml version="1.0" encoding="gb2312"?>
<!DOCTYPE beans PUBLIC "-//Spring//DTD BEAN//EN" "http://www.Springframework.org/
dtd/Spring-beans.dtd">
<beans>
<import resource="customerContext.xml" />
<import resource="systemContext.xml" />
... ...
</beans>
applicationContext.xml 文件中使用 import 的方式导入有模块配置文件,以后若有新模块的加入,那就可以简单修改这个文件了。这样大大简化了配置后期维护的复杂度,并使配置模块化,易于管理。我们来看看 Spring 是如何解析 import 配置文件的呢?
protected void importBeanDefinitionResource(Element ele) {
//获取 resource 属性
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
//如果不存在 resource 属性则不做任何处理
if (!StringUtils.hasText(location)) {
getReaderContext().error("Resource location must not be empty", ele);
return;
}
//解析系统属性,格式如: "${user.dir}"
location = environment.resolveRequiredPlaceholders(location);
Set<Resource> actualResources = new LinkedHashSet<Resource>(4);
//判定 location 是决定 URI 还是相对 URI
boolean absoluteLocation = false;
try {
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI
(location).isAbsolute();
}
catch (URISyntaxException ex) {
// cannot convert to an URI, considering the location relative
// unless it is the well-known Spring prefix "classpath*:"
}
// Absolute or relative?
//如果是绝对 URI 则直接根据地址加载对应的配置文件
if (absoluteLocation) {
try {
int importCount = getReaderContext().getReader().loadBeanDefinitions
(location, actualResources);
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from
URL location [" + location + "]");
}
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error(
"Failed to import bean definitions from URL location [" +
location + "]", ele, ex);
}
}
else {
//如果是相对地址则根据相对地址计算出绝对地址
try {
int importCount;
//Resource 存在多个子实现类,如 VfsResource、FileSystemResource 等,
//而每个 resource 的 createRelative 方式实现都不一样,所以这里先使用子类的方法
尝试解析
Resource relativeResource = getReaderContext(). getResource(). Create
Relative(location);
if (relativeResource.exists()) {
importCount = getReaderContext().getReader(). loadBeanDefinitions
(relativeResource);
actualResources.add(relativeResource);
}else {
//如果解析不成功,则使用默认的解析器 ResourcePatternResolver 进行解析
String baseLocation = getReaderContext().getResource().getURL().
toString();
importCount = getReaderContext().getReader().loadBeanDefinitions(
StringUtils.applyRelativePath(baseLocation, location),
actualResources);
}
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from
relative location [" + location + "]");
}
}
catch (IOException ex) {
getReaderContext().error("Failed to resolve current resource location", ele, ex);
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to import bean definitions from
relative location [" + location + "]",
ele, ex);
}
}
//解析后进行监听器激活处理
Resource[] actResArray = actualResources.toArray(new Resource[actualResources. size()]);
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
上面的代码不难,相信配合注释会很好理解,我们总结一下大致流程便于读者更好地梳理,在解析<import 标签时,Spring 进行解析的步骤大致如下。
(1)获取 resource 属性所表示的路径。
(2)解析路径中的系统属性,格式如“${user.dir}”。
(3)判定 location 是绝对路径还是相对路径。
(4)如果是绝对路径则递归调用 bean 的解析过程,进行另一次的解析。
(5)如果是相对路径则计算出绝对路径并进行解析。
(6)通知监听器,解析完成。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论