DefaultBeanDefinitionDocumentReader.java
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if(delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for(int i = 0; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if(node instanceof Element) {
Element ele = (Element)node;
if(delegate.isDefaultNamespace(ele)) {
//加载默认的阶段配置信息【程序入口】
this.parseDefaultElement(ele, delegate);
} else {
delegate.parseCustomElement(ele);
}
}
}
} else {
delegate.parseCustomElement(root);
}
}
parseDefaultElement(ele, delegate)该方法会根据当前节点类型做三件事情
1、导入import
例如:
<import resource="applicationContext-mybean.xml"></import>
2、alias别名
<bean name="myBean,wahaha,gagBean" class="com.wolf.bean.Mybean1"> <property name="name"> <value>郑先生</value> </property> <property name="pwd"> <value>666666888888</value> </property> </bean> <!--给myBean起别名--> <alias name="myBean" alias="gagBean,gagaBean,gagagaBean"></alias>
3、bean定义
<bean name="myBean2" class="com.wolf.bean.Mybean1"> <property name="name"> <value>郑先生2</value> </property> <property name="pwd"> <value>2222222</value> </property> </bean>
4、beans集合
对于beans集合系统会重新走doRegisterBeanDefinitions处理流程,跟程序来源一样。
parseDefaultElement(ele, delegate)代码实现如下
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if(delegate.nodeNameEquals(ele, "import")) {//导入
this.importBeanDefinitionResource(ele);
} else if(delegate.nodeNameEquals(ele, "alias")) {//别名
this.processAliasRegistration(ele);
} else if(delegate.nodeNameEquals(ele, "bean")) {//bean
this.processBeanDefinition(ele, delegate);
} else if(delegate.nodeNameEquals(ele, "beans")) {//bean集合
this.doRegisterBeanDefinitions(ele);
}
}
一、import
protected void importBeanDefinitionResource(Element ele) {
String location = ele.getAttribute("resource");
if(!StringUtils.hasText(location)) {
this.getReaderContext().error("Resource location must not be empty", ele);
} else {
location = this.getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
LinkedHashSet actualResources = new LinkedHashSet(4);
boolean absoluteLocation = false;
try {
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
} catch (URISyntaxException var11) {
;
}
int actResArray;
if(absoluteLocation) {
try {
actResArray = this.getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
} catch (BeanDefinitionStoreException var10) {
this.getReaderContext().error("Failed to import bean definitions from URL location [" + location + "]", ele, var10);
}
} else {
try {
Resource relativeResource = this.getReaderContext().getResource().createRelative(location);
//判断当前资源文件是否存在
if(relativeResource.exists()) {
//执行XmlBeanDefinitionReader的loadBeanDefinitions,跟加载资源的流程一致
//所以import资源处理操作是非常简单的
actResArray = this.getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
} else {
String baseLocation = this.getReaderContext().getResource().getURL().toString();
actResArray = this.getReaderContext().getReader().loadBeanDefinitions(StringUtils.applyRelativePath(baseLocation, location), actualResources);
}
} catch (IOException var8) {
this.getReaderContext().error("Failed to resolve current resource location", ele, var8);
} catch (BeanDefinitionStoreException var9) {
this.getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, var9);
}
}
Resource[] actResArray1 = (Resource[])actualResources.toArray(new Resource[actualResources.size()]);
//这里做了一个事件通知
this.getReaderContext().fireImportProcessed(location, actResArray1, this.extractSource(ele));
}
}
二、alias别名解析
protected void processAliasRegistration(Element ele) {
//通过当前节点的别名信息配置
//name 表示BeanName
String name = ele.getAttribute("name");
//别名信息
String alias = ele.getAttribute("alias");
boolean valid = true;
if(!StringUtils.hasText(name)) {
this.getReaderContext().error("Name must not be empty", ele);
valid = false;
}
if(!StringUtils.hasText(alias)) {
this.getReaderContext().error("Alias must not be empty", ele);
valid = false;
}
if(valid) {
try {
//XmlReaderContext-->BeanDefinitionRegistry-->GenericApplicationContext(接口BeanDefinitionRegistry)的registerAlias方法[DefaultListableBeanFactory beanFactory]
//其实就是往DefaultListableBeanFactory beanFactory中设置别名信息(SimpleAliasRegistry为具体别名注册实现)
//private final Map<String, String> aliasMap = new ConcurrentHashMap(16); 别名属性记录器
this.getReaderContext().getRegistry().registerAlias(name, alias);
} catch (Exception var6) {
this.getReaderContext().error("Failed to register alias \'" + alias + "\' for bean with name \'" + name + "\'", ele, var6);
}
this.getReaderContext().fireAliasRegistered(name, alias, this.extractSource(ele));
}
}
根据类图结构可以看到
DefaultListableBeanFactory为SimpleAliasRegistry的子类
然后在父类实现了别名的注册,子类直接使用即可。
--分部代码实现
DefaultBeanDefinitionDocumentReader.java类中持有XmlReaderContext readerContext对象
其中this.getReaderContext()其实就是去获取XmlReaderContext
protected final XmlReaderContext getReaderContext() {
return this.readerContext;
}
当拿到XmlReaderContext对象后,通过XmlReaderContext提供的getRegistry()获取注册器
XmlReaderContext.java类中持有XmlBeanDefinitionReader reader xmlBean读取器,在xmlBean读取器中获取注册器
public final BeanDefinitionRegistry getRegistry() {
return this.reader.getRegistry();
}
AbstractBeanDefinitionReader.java类中持有
private final BeanDefinitionRegistry registry//BeanDefinitionRegistry为一个接口
public final BeanDefinitionRegistry getRegistry() {
return this.registry;
}
GenericApplicationContext.java持有DefaultListableBeanFactory beanFactory
public void registerAlias(String beanName, String alias) {
this.beanFactory.registerAlias(beanName, alias);
}
SimpleAliasRegistry.java
private final Map<String, String> aliasMap = new ConcurrentHashMap(16);
public void registerAlias(String name, String alias) {
if(alias.equals(name)) {
this.aliasMap.remove(alias);
} else {
String registeredName = (String)this.aliasMap.get(alias);
if(registeredName != null) {
if(registeredName.equals(name)) {
return;
}
if(!this.allowAliasOverriding()) {
throw new IllegalStateException("Cannot register alias \'" + alias + "\' for name \'" + name + "\': It is already registered for name \'" + registeredName + "\'.");
}
}
this.checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name);
}
}
总结:其实别名的注册思路很简单。就是在beanFactory容器中去查找当前beanName是否存在别名,如果存在则直接return;如果别名与beanName的名称相同时也return;
这里还加入了一个逻辑就是判断别名是否能够被替换在目前的代码实现直接返回了true,也就是说默认情况可以直接替换别名的。
protected boolean allowAliasOverriding() { return true; }
this.checkForAliasCircle(name, alias)
这里做了一个验证,就是验证当前注册的别名是否被其他的beanName注册过,如果注册过会抛出
throw new IllegalStateException("Cannot register alias \'" + alias + "\' for name \'" + name + "\': Circular reference - \'" + name + "\' is a direct or indirect alias for \'" + alias + "\' already")异常
三、beans处理
beans处理逻辑也比较简单
直接调用了this.doRegisterBeanDefinitions(ele)逻辑,然后我们跟踪代码,发现跟处理rootElement逻辑相同。
protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; this.delegate = this.createDelegate(this.getReaderContext(), root, parent); if(this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute("profile"); if(StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; "); if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if(this.logger.isInfoEnabled()) { this.logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource()); } return; } } } this.preProcessXml(root); this.parseBeanDefinitions(root, this.delegate); this.postProcessXml(root); this.delegate = parent; }
四、bean标签处理
TIPS:针对bean标签的处理逻辑相对比较复杂,这里要深入分析。
【接】基于XmlBeanFactory加载bean分析:parseDefaultElement(二)