6Spring 源码学习 ~ 默认标签的解析之 import 标签的解析
Posted 戴泽supp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了6Spring 源码学习 ~ 默认标签的解析之 import 标签的解析相关的知识,希望对你有一定的参考价值。
import 标签的解析与注册
一、import 标签的使用
对于 Spring 配置文件的编写,经历过大型项目的人,都有种恐惧心理,因为随着项目业务的增多,配置文件会急剧膨胀,把所有配置写在同一个文件里,显然会对配置的管理造成困难。这个时候,分模块是大多数人能想到的方法,使用 import 是个好方法,如我们可以构造这样的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- <import resource="classpath:spring/app-context.xml"/>-->
<!-- <import resource="../spring/app-context.xml"/>-->
<import resource="classpath*:spring/app-context.xml"/>
</beans>
测试(上面两种方式皆可):
package com.luo.spring.guides.helloworld.imports;
import com.luo.spring.guides.helloworld.common.TestBean;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author : archer
* @date : Created in 2022/10/25 14:46
* @description :
*/
public class Main
public static void main(String[] args)
ApplicationContext bf = new ClassPathXmlApplicationContext("import/applicationContext.xml");
TestBean test = (TestBean) bf.getBean("testBean");
System.out.println(test);
二、import 标签的解析
入口源码:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT))
importBeanDefinitionResource(ele);
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT))
processAliasRegistration(ele);
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT))
processBeanDefinition(ele, delegate);
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT))
// recurse
doRegisterBeanDefinitions(ele);
具体解析函数 importBeanDefinitionResource:
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;
// Resolve system properties: e.g. "$user.dir"
//解析系统属性,如:$user.dir
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
Set<Resource> actualResources = new LinkedHashSet<>(4);
// Discover whether the location is an absolute or relative 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?
//绝对路径,则直接根据地址加载相应配置文件
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
// No URL -> considering resource location as relative to the current file.
//相对路径,则根据相对路径地址,计算出绝对路径地址,再去加载
try
int importCount;
//Resource 存在多个子实现类,如 VfsResource、FileSystenResource 等
//每个 resource 的 createRelative 方式实现都不一样,所以这里先使用子类的方法尝试解析
Resource relativeResource = getReaderContext().getResource().createRelative(location);
if (relativeResource.exists())
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
else
//解析不成功,则使用默认的AppClassLoader 去解析,最终结果大致如下:
//baseLocation:file:/D:/justforfun/archer-spring/spring-guides/build/resources/test/beanfactory-test.xml
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、判断是否是绝对路径
- 4、如果是绝对路径,则递归调用 bean 的解析过程,进行另一次解析
- 5、如果是相对路径,则计算出绝对路径,并进行解析
- 6、通知监听器,解析完成
以上就是 import 标签的解析逻辑。
以上是关于6Spring 源码学习 ~ 默认标签的解析之 import 标签的解析的主要内容,如果未能解决你的问题,请参考以下文章
4Spring 源码学习 ~ 默认标签的解析之 Bean 标签注册
7Spring 源码学习 ~ 默认标签的解析之嵌入式 beans 标签的解析