acm highcharts encoding deployment terminal 河南普通话考试报名官网 进销存源码 jquery循环遍历 jquery去除空格 java清空数组 python编程练习题 如何升级python java微服务架构 docker启动容器 mysql教程 python字典类型 python的array python中文教程 python可视化编程 java基础教学 java中的数据类型 java怎么使用 java中tostring方法 linux命令行 opengl编程指南 高效能人士的七个习惯下载 js数组删除指定元素 bash命令 苹果剪辑 自制题库答题考试软件 海妖花粉哪里多 复制到剪贴板 lol体验服转换器 英雄联盟崩溃 微信昵称找人的软件 多面硬币 pdf安装包官方下载 ps蒙版抠图详细教程 一键换肤大师 兽之祝福
当前位置: 首页 > 学习教程  > 编程语言

Spring之默认标签的解析(十)alias、import、beans等标签的解析

2020/12/5 10:06:07 文章标签:

Spring之默认标签的解析(十)alias、import、beans等标签的解析alias标签的解析import标签的解析嵌入式beans等标签的解析通过上面较长的篇幅我们终于分析完了默认标签中对 bean 标签的处理,那么我们之前提到过,对配置文件的解析包…

Spring之默认标签的解析(十)alias、import、beans等标签的解析

  • alias标签的解析
  • import标签的解析
  • 嵌入式beans等标签的解析

通过上面较长的篇幅我们终于分析完了默认标签中对 bean 标签的处理,那么我们之前提到过,对配置文件的解析包括对import标签、 alias标签、 bean标签、 beans标签的处理,现在我们已经完成了最重要 也是最核心的功能,其他的解析步骤骤也都是围绕第 3 个解析而进行的 。在分析了第 3个解析步骤后,再回过头来看着对 alias标签的解析。

alias标签的解析

在对 bean 进行定义时,除了使用 id 属性来指定名称之外,为了提供多个名称,可以使用 alias标签来指定。 而所有的这些名称都指向同一个bean,在某些情况下提供别名非常有用,比如为了让应用的每一个组件能更容易地对公共组件进行引用 。
然而,在定义 bean时就指定所有的别名并不是总是恰当的。 有时我们期望能在当前位置为那些在另lj处定义的 bean 引人别名。 在 XMLf日置文件中,可用单独的元素来完成bean别名的定义。 如配置文件文件中定义了一个 JavaBean:

	<bean id="testBean" class="com.test"/>

要给这个 JavaBean增加别名,以方便不同对象来调用。 我们就可以直接使用 bean标签中的name 属性:

	<bean id="testBean" name="testBean, teatBean2" class="com.test"/>

同样, Spring 还有另外 一 种卢明别名的方式:

	<bean id="testBean" class="com.test"/>
	<alias name="teatBean" alias="testBean, teatBean2"/>

考虑一个更为具体的例子,组件 A 在 XML 配置文件中定义了一个名为 componentA 的DataSource 类型的 bean,但组件B 却想在其 XML 文件中以 componentB 命名来引用此bean。 而且在主程序 MyApp 的 XML配置文件中,希望以 myApp 的名字来引用此 bean。 最后容器加载3个XML 文件来生成最终的 ApplicationContext。 在此情 下,可通过在配置文件中添加下

    <alias name="componentA" alias="componentB"/>
	<alias name="componentA" alias="MyApp"/>

这样一来,每个组件及主程序就可通过唯一名字来引用同一个数据源而互不干扰 。在之前的文档已经讲过了别于 bean 中 name 元素的解析,那么我们现在再来深入分析下对于 alias标签的解析过程。

protected void processAliasRegistration(Element ele) {
	String name = ele.getAttribute(NAME_ATTRIBUTE);
	String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
	boolean valid = true;
	if (!StringUtils.hasText(name)) {
		getReaderContext().error("Name must not be empty", ele);
		valid = false;
	}
	if (!StringUtils.hasText(alias)) {
		getReaderContext().error("Alias must not be empty", ele);
		valid = false;
	}
	if (valid) {
		try {
			getReaderContext().getRegistry().registerAlias(name, alias);
		}
		catch (Exception ex) {
			getReaderContext().error("Failed to register alias '" + alias +
					"' for bean with name '" + name + "'", ele, ex);
		}
		getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
	}
}

可以发现,跟之前讲过的 bean 中的 alias解析大同小异,都是将别名与 beanName组成一 对注册至registry中。 这里不再赘述。

import标签的解析

对于 Spring 配置文件的编 写 , 我想,经历过庞大项目的人,都有那种恐惧的心理,太多的配置文件了 。 所以,分模块是我们经常想到的方法。比如使用 import标签,例如我们可以构造这样的 Spring配置文件:

  • applicationContext.xml
<?xml version="1.0" encoding=”gb2312"?>
<!DOCTYPE beans PUBLIC "-//Spring//DTD BEAN//EN" "http://www.springframework.org/dtd/Spr工ng-beaas.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);
		if (!StringUtils.hasText(location)) {
			getReaderContext().error("Resource location must not be empty", ele);
			return;
		}
	
		// 解析系统属性,格式如 "${user.dir}"
		location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
	
		Set<Resource> actualResources = new LinkedHashSet<>(4);
	
		// 判定该位置是绝对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*:"
		}
	
		// 如果是绝对路径则直接根据地质加载对应的配置文件
		if (absoluteLocation) {
			try {
				int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
				if (logger.isTraceEnabled()) {
					logger.trace("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存在多个字实现类,如VfsResoure、FileSystemResource等
				 * 每个resource的createRelative 方式实现都不一样,所以这里先试用子类的方法尝试解析
				 */ 
				 
				Resource relativeResource = getReaderContext().getResource().createRelative(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.isTraceEnabled()) {
					logger.trace("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[0]);
		getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
	}

配合注释会很好理解,总结一下大致流程:

  1. 获取 resource属性所表示的路径。
  2. 解析路径中的系统属性,格式如“${ user.dir}”。
  3. 判定 location是绝对路径还是相对路径。
  4. 如果是绝对路径则递归调用 bean 的解析过程,进行另一次的解析 。
  5. 如果是相对路径则计算出绝对路径并进行解析。
  6. 通知监听器,解析完成 。

嵌入式beans等标签的解析

对于嵌入式的 beans标签,相信大家使用过或者至少接触过,非常类似于 import标签所提供的功能,使用如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans ... ... >
    <bean id="test" class="com.Test"/>
    
    <beans>
    	.........
    </beans>
</beans>

对于嵌入式 beans 标签来讲,并没有太多可讲,无非是递归调用 beans 的解析过程,重新调用doRegisterBeanDefinitions函数。


本文链接: http://www.dtmao.cc/news_show_450152.shtml

附件下载

上一篇:A. Strange Functions

下一篇:集合介绍

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?