继续接着Spring 加载、解析applicationContext.xml 流程解析 import 、 alias、beans 标签。
DefaultBeanDefinitionDocumentReader.parseDefaultElement()
<import resource="user-appalicationContext.xml"/>
入口类、方法DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource();
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);
boolean absoluteLocation = false;
try {
// 判断 location 是绝对路径还是相对路径
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 {
//加载xml配置文件,并解析资源
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);
if (relativeResource.exists()) {
//加载xml文件,并解析
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
}else {
// 获取URL 路径,并解析文件
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));
}
<bean id="user" class="cn.com.infcn.test.User"></bean>
<alias name="user" alias="myUser" />
DefaultBeanDefinitionDocumentReader.processAliasRegistration()
protected void processAliasRegistration(Element ele) {
//获取 name属性
String name = ele.getAttribute(NAME_ATTRIBUTE);
//获取 alias 属性
String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
boolean valid = true;
//验证 name 是否为空
if (!StringUtils.hasText(name)) {
getReaderContext().error("Name must not be empty", ele);
valid = false;
}
//验证 alias 是否为空
if (!StringUtils.hasText(alias)) {
getReaderContext().error("Alias must not be empty", ele);
valid = false;
}
if (valid) {
try {
//把 alias 注册到 SimpleAliasRegistry.aliasMap 中
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));
}
}
public class SimpleAliasRegistry implements AliasRegistry {
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
@Override
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
if (alias.equals(name)) {
this.aliasMap.remove(alias);
}else {
String registeredName = this.aliasMap.get(alias);
if (registeredName != null) {
if (registeredName.equals(name)) {
// An existing alias - no need to re-register
return;
}
if (!allowAliasOverriding()) {
throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
}
checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name);
}
}
protected boolean allowAliasOverriding() {
return true;
}
......
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<bean id="user" class="cn.com.infcn.test.User"></bean>
<beans>
......
</beans>
</beans>
beans 标签解析 又调用了doRegisterBeanDefinitions() 方法,这个方法在Spring 加载、解析applicationContext.xml 流程中已经介绍过了。
跟import 解析都类似。又相当于重新执行解析了一边 bean 标签一样。