接着上一节,讲到parseBeanDefinitions()方法,位于DefaultBeanDefinitionDocumentReader类中
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) { //xml元素节点
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) { //元素节点使用的是 spring默认的xml命名空间
parseDefaultElement(ele, delegate); //【入】,解析该节点
}
else { //如果不是spring默认的xml命名空间,则使用用户自定义的解析规则解析元素节点
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
它对xml的第一层子节点,进行了遍历,并且解析,parseDefaultElement()方法
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { //<import>导入元素
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { //<alias>别名元素
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {//<bean>节点
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
由于代码量太多,我们重点关注 <bean>节点的解析,processBeanDefinition()方法
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//...Holder是对 BeanDefinition的封装,即Bean定义的封装类
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); //具体的节点解析 又delegate完成
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance. 向spring IOC容器注册解析到的 bean定义,这是bean定义向IOC容器注册的入口
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
// Send registration event. 完成向spring IOC容器注册解析得到的Bean定义之后,发送注册事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
该代码,就是bean从xml到spring的最为【核心】的代码,首先该方法是xml解析的入口,具体的解析交给了delegate对象进行解析,而且解析内容很多,所以这里也不阐述了,我们重点关注如何向spring ioc容器注册。
对于BeanDefinitionHolder上面注释中写到了,是对BeanDefinition的封装,代码内容很多。
BeanDefinitinoReaderUtils类中的registerBeanDefinition()方法
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
//获得BeanDefinitino的名字
String beanName = definitionHolder.getBeanName();
//【入】
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
//获取别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
//注册别名,别名的存在也很有意思,在后期依赖注入getBean()有很大作用
}
}
}
同样该方法是一个入口方法,主要处理了别名,它的具体注册交给了DefaultListableBeanFactory类
该类的继承关系图:
此类图很重要,我们要做到熟悉,在第二章DI中,我们会着重研究该类图,目前我们需要知道BeanDefinitino保存在了BeanFactory类的底层:DefaultListableBeanFactory类中
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
...
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) { //已经存在
...
this.beanDefinitionMap.put(beanName, beanDefinition); //【放入】
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition); //【放入】
//更新名字,直接扩容,然后全部添加,可能这样效率不高
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
注意,全部放在了本类的beanDefinitionMap集合中!,bean就成功注册到了spring ioc容器中,可以通过bean的名字,获得beanDefintion对象,获得Bean的信息。
注册完毕,回到DefaultBeanDefinitionDocumentReader的processBeanDefinitino()方法,它在注册完bean之后,需要发送注册事件。也就是调用fireComponentRegistered()方法
最后,回到refresh()方法中,第二步:refreshBeanFactory()核心内容完成,现在更新beanFactory字段信息。beanFactory保存在第二层中,在refresh()方法(它存在于第一层AbstractApplicationContext类中),它getBeanFactory()方法,保存在局部变量中,余下的3,4,5,6,11等步骤调用的方法,都是使用beanFactory作为参数传入。