import标签的解析是调用的org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#importBeanDefinitionResource方法,源码如下:
protected void importBeanDefinitionResource(Element ele) {
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
if (!StringUtils.hasText(location)) {
getReaderContext().error("Resource location must not be empty", ele);
return;
}
//从上下文获取系统属性,解析${}占位符并使用相应的属性值来代替
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
Set<Resource> actualResources = new LinkedHashSet<Resource>(4);
//这里是对import的位置做出判断,是相对还是绝对路径,默认是相对
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.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 {
// No URL -> considering resource location as relative to the current file.
try {
int importCount;
//将路径配置转为资源
Resource relativeResource = getReaderContext().getResource().createRelative(location);
//如果可以获取到资源,则回调到AbstractBeanDefinitionReader的loadBeanDefinitions方法进行加载
if (relativeResource.exists()) {
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
}
else {
//获取不到资源,则加上基础路径,再进行加载操作
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()]);
//调用事件监听器ReaderEventListener#importProcessed()方法 通知处理的import的结果
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
其中有一步获取系统属性,解析${}占位符并使用相应的属性值来代替,这个的主要场景是资源文件可能是按环境分离的,如:
<import resource="com/test/dao/dao-${test}.xml" />
这里可以从系统属性和环境变量中获取,类似于:System.getProperties(),System.getenv()
这些属性,在上下文中已经存在,
如系统属性:
os.name
如环境变量:
JAVA_HOME
最后一步,都会调到org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource)这个方法解析xml文件,具体解析又回到了bean的定义加载,因为本身也在解析xml文件流程中,只是里面又嵌套了xml文件,递归调用,可看这篇文章:https://blog.csdn.net/matt8/article/details/106352083