学习记录,以供以后查阅!参考书籍《Spring技术内幕》。
本篇文章以Spring 5.2.15.RELEASE版本的FileSystemXmlApplicationContext容器为例进行梳理。
1、IoC容器初始化过程概述
IOC容器的初始化过程,简单来说是由refresh方法完成初始化工作。
具体来讲包括如下三个步骤:
1、Resource资源的定位。(简单的讲就是读取xml文件中的bean配置,获取数据流的过程)
2、BeanDefinition的载入和解析。(简单讲就是把xml中bean的定义,转化为IOC容器识别的数据格式,这个格式就是BeanDefinition)
3、向IOC容器注册BeanDefinition的过程。(简单的讲就是把这些BeanDefinition,转换为对象注册进IOC容器的过程)
1.1 FileSystemXmlApplicationContext 继承关系图
1.2 FileSystemXmlApplicationContext 源码
从源码中可以看到容器的初始化工作是通过refresh()方法来启动的
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
public FileSystemXmlApplicationContext() {
}
public FileSystemXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
// configLocation包含的是BeanDfinition所在的文件路径
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
this(new String[]{configLocation}, true, (ApplicationContext)null);
}
public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, (ApplicationContext)null);
}
public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
this(configLocations, true, parent);
}
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
this(configLocations, refresh, (ApplicationContext)null);
}
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
// 保存BeanDfinition所在的文件路径
this.setConfigLocations(configLocations);
if (refresh) {
// 启动容器初始化
this.refresh();
}
}
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
}
1.3 refresh()方法流程图
1.4 refresh()方法源码
refresh()在FileSystemXmlApplicationContext类的父类AbstractApplicationContext中实现
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
1.5 BeanFactory容器的创建
BeanFactory的创建过程如下:
1、refresh()方法调用this.obtainFreshBeanFactory()方法。
2、obtainFreshBeanFactory()调用了refreshBeanFactory()方法。
3、refreshBeanFactory()方法创建一个DefaultListableBeanFactory。
1.6 refreshBeanFactory()流程
如果容器存在,则销毁和关闭
创建IOC容器DefaultListableBeanFactory
启动对BeanDefinition的载入
protected final void refreshBeanFactory() throws BeansException {
// 如果容器存在,则销毁和关闭
if (this.hasBeanFactory()) {
this.destroyBeans();
this.closeBeanFactory();
}
try {
// 创建IOC容器DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
beanFactory.setSerializationId(this.getId());
this.customizeBeanFactory(beanFactory);
// 启动对BeanDefinition的载入
this.loadBeanDefinitions(beanFactory);
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}
1.7 创建DefaultListableBeanFactory容器
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(this.getInternalParentBeanFactory());
}
2、Resource资源的定位
2.1 创建XmlBeanDefinitionReader
1、初始化读取器XmlBeanDefinitionReader,并通过回调设置到BeanFactory中。
2、通过XmlBeanDefinitionReader加载资源。
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建XmlBeanDefinitionReader,并通过回调设置到BeanFactory中去
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
// 这里设置XmlBeanDefinitionReader,为XmlBeanDefinitionReader配置
// ResourceLoader,因为defaultResourceLoader是父类,所以this可以直接被使用
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
this.initBeanDefinitionReader(beanDefinitionReader);
// 启动Bean定义信息的载入过程
this.loadBeanDefinitions(beanDefinitionReader);
}
2.2 获得资源合集,通过XmlBeanDefinitionReader读取资源
AbstractXmlApplicationContext中loadBeanDefinitions实现
首先,获得Resource/String定位资源合集。
然后,调用XmlBeanDefinitionReader的loadBeanDefinitions读取资源。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 以Resource的方式获得配置文件的资源位置
Resource[] configResources = this.getConfigResources();
if (configResources != null) {
// 调用XmlBeanDefinitionReader来读取资源进行载入
reader.loadBeanDefinitions(configResources);
}
// 以String的形式获得配置文件的位置
String[] configLocations = this.getConfigLocations();
if (configLocations != null) {
// 调用XmlBeanDefinitionReader来读取资源进行载入
reader.loadBeanDefinitions(configLocations);
}
}
2.3 载入以Resource的方式获得的资源
AbstractBeanDefinitionReader中loadBeanDefinitions实现
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
// 如果Resource为空,则停止BeanDefinition的载入
// 然后启动载入BeanDefinition的过程,
// 这个过程遍历整个Resource集合所包含的BeanDefinition信息
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
Resource[] var3 = resources;
int var4 = resources.length;
for(int var5 = 0; var5 < var4; ++var5) {
Resource resource = var3[var5];
count += this.loadBeanDefinitions((Resource)resource);
}
return count;
}
3、BeanDefinition的载入和解析
XmlBeanDefinitionReader中 loadBeanDefinitions(Resource resource)方法的实现。
1、获取文件输入流InputStream
2、获得XML读取流InputSource
3、取得XML文件的Document对象
4、调用registerBeanDefinitions方法解析XML
// Resource封装了对XML文件的I/O操作
// Reader读取器可以打开I/O操作得到XML的文件对象
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return this.loadBeanDefinitions(new EncodedResource(resource));
}
// 载入XML形式的BeanDefinition
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (this.logger.isInfoEnabled()) {
this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!((Set)currentResources).add(encodedResource)) {
throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
} else {
int var5;
try {
// 这里得到XML文件,并得到IO的InputSource准备进行读取
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} finally {
inputStream.close();
}
} catch (IOException var15) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
} finally {
((Set)currentResources).remove(encodedResource);
if (((Set)currentResources).isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
return var5;
}
}
// 具体的读取过程如下
// 这是从特定的XML文件中实际载入BeanDefinition的地方
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
// 这里取得XML文件的Document对象
Document doc = this.doLoadDocument(inputSource, resource);
// 这里启动的是对BeanDefinition解析的详细过程,这个解析会用到Spring的Bean配置规则
return this.registerBeanDefinitions(doc, resource);
} catch (BeanDefinitionStoreException var4) {
throw var4;
} catch (SAXParseException var5) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);
} catch (SAXException var6) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);
} catch (ParserConfigurationException var7) {
throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);
} catch (IOException var8) {
throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);
} catch (Throwable var9) {
throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);
}
}
3.1 Spring的BeanDefinition是怎样按照Spring的Bean语义要求进行解析并转化为容器内部数据结构的
具体过程是由BeanDefinitionDocumentReader来完成的,这个registerBeanDefinition还对载入的Bean数量进行了统计。如下所示。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 这里得到BeanDefinitionDocumentReader来对XML的BeanDefinition进行解析
BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
int countBefore = this.getRegistry().getBeanDefinitionCount();
// 具体的解析过程在这个registerBeanDefinitions中完成
documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
return this.getRegistry().getBeanDefinitionCount() - countBefore;
}
3.2 BeanDefinitionDocumentReader的创建
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return (BeanDefinitionDocumentReader)BeanUtils.instantiateClass(this.documentReaderClass);
}
得到documentReader以后,为具体的Spring Bean的解析过程准备好了数据
具体的解析过程是由processBeanDefinition方法完成的,调用方法栈如下
3.3 调用processBeanDefinition方法解析BeanDefinition
processBeanDefinition是处理BeanDefinition的地方
具体的处理委托给BeanDefinitionParserDelegate来完成
ele对应在Spring BeanDefinition中定义的XML元素
BeanDefinitionHolder是BeanDefinition对象的封装类
封装了BeanDefinition,Bean的名字和别名
用它来完成向IOC容器注册
得到这个BeanDefinitionHolder就意味着BeanDefinition
是通过BeanDefinitionParserDelegate对XML元素的信息
按照Spring的Bean规则进行解析得到的
最后把BeanDefinitionHolder注册到IOC容器
注册完成,发送消息
// 这里是处理BeanDefinition的地方,
// 具体的处理委托给BeanDefinitionParserDelegate来完成
// ele对应在Spring BeanDefinition中定义的XML元素
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// BeanDefinitionHolder是BeanDefinition对象的封装类
// 封装了BeanDefinition,Bean的名字和别名
// 用它来完成向IOC容器注册
// 得到这个BeanDefinitionHolder就意味着BeanDefinition
// 是通过BeanDefinitionParserDelegate对XML元素的信息
// 按照Spring的Bean规则进行解析得到的
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 这里是向IOC容器注册解析得到BeanDefinition的地方
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException var5) {
this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
}
// 在BeanDefinition向IOC容器注册完以后,发送消息
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
3.4 详细的XML解析过程
BeanDefinitionParserDelegate类中包含了对各种Spring Bean定义规则的处理
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return this.parseBeanDefinitionElement(ele, (BeanDefinition)null);
}
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 这里取得在<bean>元素中定义的id、name、aliase属性的值
String id = ele.getAttribute("id");
String nameAttr = ele.getAttribute("name");
List<String> aliases = new ArrayList();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(id) && !aliases.isEmpty()) {
beanName = (String)aliases.remove(0);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
this.checkNameUniqueness(beanName, aliases, ele);
}
// 这个方法会引发对Bean元素的详细解析
AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
} else {
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
}
} catch (Exception var9) {
this.error(var9.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
} else {
return null;
}
}
3.5 具体生成BeanDefinition的地方
对BeanDefinition元素处理的代码
AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
// 这里只读取定义的<bean>中设置的class名字,然后载入到BeanDefinition中去
// 只是做个记录,并不涉及对象的实例化过程
// 对象的实例化实际上是在依赖注入时完成的
String className = null;
if (ele.hasAttribute("class")) {
className = ele.getAttribute("class").trim();
}
String parent = null;
if (ele.hasAttribute("parent")) {
parent = ele.getAttribute("parent");
}
try {
// 这里生成需要的BeanDefinition对象,为Bean定义信息的载入做准备
AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
// 这里对当前的Bean元素进行属性解析,并设置description的信息
this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
// 从名字可以清楚的看到,这里是对各种<bean>元素的信息进行解析的地方
this.parseMetaElements(ele, bd);
this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析<bean>的构造函数设置
this.parseConstructorArgElements(ele, bd);
// 解析<bean>的property设置
this.parsePropertyElements(ele, bd);
this.parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(this.extractSource(ele));
AbstractBeanDefinition var7 = bd;
return var7;
// 下面这些异常是在配置Bean出现问题时经常会看到的,原来是在这里抛出的,这些检查是在
// createBeanDefinition时进行的,会检查Bean的class设置是否正确,比如这个类是否能找到
} catch (ClassNotFoundException var13) {
this.error("Bean class [" + className + "] not found", ele, var13);
} catch (NoClassDefFoundError var14) {
this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
} catch (Throwable var15) {
this.error("Unexpected failure during bean definition parsing", ele, var15);
} finally {
this.parseState.pop();
}
return null;
}
3.6 举一个对property进行解析的例子
举一个对property进行解析的例子,来完成对整个BeanDefinition载入过程的分析,还是在类BeanDefinitionParserDelegate的代码中,一层一层地对BeanDefinition中的定义进行解析,比如从属性元素集合到具体的每一个属性元素,然后才是对具体的属性值的处理。根据解析结果,对这些属性值的处理会被封装成PropertyValue对象并设置到BeanDefinition对象中去。
这里对指定Bean元素的property子元素集合进行解析
遍历所有Bean元素下定义的property元素
在判断是property元素后,对该元素进行解析
// 这里对指定Bean元素的property子元素集合进行解析
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
// 遍历所有Bean元素下定义的property元素
for(int i = 0; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if (this.isCandidateElement(node) && this.nodeNameEquals(node, "property")) {
// 在判断是property元素后,对该元素进行解析
this.parsePropertyElement((Element)node, bd);
}
}
}
3.7 解析property元素
public void parsePropertyElement(Element ele, BeanDefinition bd) {
// 这里取得property的名字
String propertyName = ele.getAttribute("name");
if (!StringUtils.hasLength(propertyName)) {
this.error("Tag 'property' must have a 'name' attribute", ele);
} else {
this.parseState.push(new PropertyEntry(propertyName));
try {
// 如果同一个Bean中已经有同名的property存在,则不进行解析,直接返回。
// 也就是说,如果同一个Bean中有同名的property设置,那么只有第一个起作用
if (bd.getPropertyValues().contains(propertyName)) {
this.error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
// 这里是解析property值的地方,返回的对象对应对Bean定义的property属性设置的解析结果。
// 这个解析结果会封装到PropertyValue对象中,然后设置到BeanDefinitionHolder中去
Object val = this.parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
this.parseMetaElements(ele, pv);
pv.setSource(this.extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
} finally {
this.parseState.pop();
}
}
}
3.8 获取property元素的值
// 这里取得property元素的值,也许是一个list或其他
@Nullable
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
String elementName = propertyName != null ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element";
NodeList nl = ele.getChildNodes();
Element subElement = null;
for(int i = 0; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if (node instanceof Element && !this.nodeNameEquals(node, "description") && !this.nodeNameEquals(node, "meta")) {
if (subElement != null) {
this.error(elementName + " must not contain more than one sub-element", ele);
} else {
subElement = (Element)node;
}
}
}
// 这里判断property的属性,是ref海水value,不允许同时是ref和value
boolean hasRefAttribute = ele.hasAttribute("ref");
boolean hasValueAttribute = ele.hasAttribute("value");
if (hasRefAttribute && hasValueAttribute || (hasRefAttribute || hasValueAttribute) && subElement != null) {
this.error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
}
// 如果是ref,创建一个ref的数据对象RuntimeBeanReference,这个对象封装了ref的信息
if (hasRefAttribute) {
String refName = ele.getAttribute("ref");
if (!StringUtils.hasText(refName)) {
this.error(elementName + " contains empty 'ref' attribute", ele);
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
ref.setSource(this.extractSource(ele));
return ref;
// 如果是value,创建一个value的数据对象TypedStringvalue,这个对象封装了value的信息
} else if (hasValueAttribute) {
TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute("value"));
valueHolder.setSource(this.extractSource(ele));
return valueHolder;
// 如果还有子元素,触发对子元素的解析
} else if (subElement != null) {
return this.parsePropertySubElement(subElement, bd);
} else {
this.error(elementName + " must specify a ref or value", ele);
return null;
}
}
3.9 解析property元素的子元素
@Nullable
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd) {
return this.parsePropertySubElement(ele, bd, (String)null);
}
@Nullable
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
if (!this.isDefaultNamespace((Node)ele)) {
return this.parseNestedCustomElement(ele, bd);
} else if (this.nodeNameEquals(ele, "bean")) {
BeanDefinitionHolder nestedBd = this.parseBeanDefinitionElement(ele, bd);
if (nestedBd != null) {
nestedBd = this.decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
}
return nestedBd;
} else if (this.nodeNameEquals(ele, "ref")) {
String refName = ele.getAttribute("bean");
boolean toParent = false;
if (!StringUtils.hasLength(refName)) {
refName = ele.getAttribute("parent");
toParent = true;
if (!StringUtils.hasLength(refName)) {
this.error("'bean' or 'parent' is required for <ref> element", ele);
return null;
}
}
if (!StringUtils.hasText(refName)) {
this.error("<ref> element contains empty target attribute", ele);
return null;
} else {
RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
ref.setSource(this.extractSource(ele));
return ref;
}
} else if (this.nodeNameEquals(ele, "idref")) {
return this.parseIdRefElement(ele);
} else if (this.nodeNameEquals(ele, "value")) {
return this.parseValueElement(ele, defaultValueType);
} else if (this.nodeNameEquals(ele, "null")) {
TypedStringValue nullHolder = new TypedStringValue((String)null);
nullHolder.setSource(this.extractSource(ele));
return nullHolder;
} else if (this.nodeNameEquals(ele, "array")) {
return this.parseArrayElement(ele, bd);
} else if (this.nodeNameEquals(ele, "list")) {
return this.parseListElement(ele, bd);
} else if (this.nodeNameEquals(ele, "set")) {
return this.parseSetElement(ele, bd);
} else if (this.nodeNameEquals(ele, "map")) {
return this.parseMapElement(ele, bd);
} else if (this.nodeNameEquals(ele, "props")) {
return this.parsePropsElement(ele);
} else {
this.error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
return null;
}
}
3.10 属性之list元素的解析
public List<Object> parseListElement(Element collectionEle, @Nullable BeanDefinition bd) {
String defaultElementType = collectionEle.getAttribute("value-type");
NodeList nl = collectionEle.getChildNodes();
ManagedList<Object> target = new ManagedList(nl.getLength());
target.setSource(this.extractSource(collectionEle));
target.setElementTypeName(defaultElementType);
target.setMergeEnabled(this.parseMergeAttribute(collectionEle));
// 具体的List元素的解析过程
this.parseCollectionElements(nl, target, bd, defaultElementType);
return target;
}
protected void parseCollectionElements(NodeList elementNodes, Collection<Object> target, @Nullable BeanDefinition bd, String defaultElementType) {
// 遍历所有的元素节点,并判断其类型是否为Element
for(int i = 0; i < elementNodes.getLength(); ++i) {
Node node = elementNodes.item(i);
if (node instanceof Element && !this.nodeNameEquals(node, "description")) {
// 加入到target中,target是一个ManageList,同时触发对下一层子元素的解析过程
target.add(this.parsePropertySubElement((Element)node, bd, defaultElementType));
}
}
}
4、向IoC容器注册BeanDefinition
4.1容器的数据结构
在这些动作完成以后,用户定义的BeanDefinition信息已经在IoC容器内建立起了自己的数据结构以及相应的数据表示,但此时这些数据还不能供IoC容器直接使用,需要在IoC容器中对这些BeanDefinition数据进行注册。
这个注册为IoC容器提供了更友好的使用方式,在DefaultListableBeanFactory中,是通过一个HashMap来持有载入的BeanDefinition的,这个HashMap的定义在DefaultListableBeanFactory中可以看到。
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
@Nullable
private static Class<?> javaxInjectProviderClass;
private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories;
@Nullable
private String serializationId;
private boolean allowBeanDefinitionOverriding = true;
private boolean allowEagerClassLoading = true;
@Nullable
private Comparator<Object> dependencyComparator;
private AutowireCandidateResolver autowireCandidateResolver;
private final Map<Class<?>, Object> resolvableDependencies;
// 通过这个HashMap来持有载入的BeanDefinition
private final Map<String, BeanDefinition> beanDefinitionMap;
private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders;
private final Map<Class<?>, String[]> allBeanNamesByType;
private final Map<Class<?>, String[]> singletonBeanNamesByType;
private volatile List<String> beanDefinitionNames;
private volatile Set<String> manualSingletonNames;
@Nullable
private volatile String[] frozenBeanDefinitionNames;
private volatile boolean configurationFrozen;
public DefaultListableBeanFactory() {
this.autowireCandidateResolver = SimpleAutowireCandidateResolver.INSTANCE;
this.resolvableDependencies = new ConcurrentHashMap(16);
// beanDefinitionMap的初始化使用了ConcurrentHashMap
this.beanDefinitionMap = new ConcurrentHashMap(256);
this.mergedBeanDefinitionHolders = new ConcurrentHashMap(256);
this.allBeanNamesByType = new ConcurrentHashMap(64);
this.singletonBeanNamesByType = new ConcurrentHashMap(64);
this.beanDefinitionNames = new ArrayList(256);
this.manualSingletonNames = new LinkedHashSet(16);
}
4.2调用注册方法
通过前面的解析后,把解析结果放到BeanDefinition对象中,并设置到BeanDefinitionHolder对象中去,用BeanDefinitionHolder来完成向IOC容器注册。
// 这里是处理BeanDefinition的地方,
// 具体的处理委托给BeanDefinitionParserDelegate来完成
// ele对应在Spring BeanDefinition中定义的XML元素
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// BeanDefinitionHolder是BeanDefinition对象的封装类
// 封装了BeanDefinition,Bean的名字和别名
// 用它来完成向IOC容器注册
// 得到这个BeanDefinitionHolder就意味着BeanDefinition
// 是通过BeanDefinitionParserDelegate对XML元素的信息
// 按照Spring的Bean规则进行解析得到的
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 这里是向IOC容器注册解析得到BeanDefinition的地方
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException var5) {
this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
}
// 在BeanDefinition向IOC容器注册完以后,发送消息
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
String[] var4 = aliases;
int var5 = aliases.length;
for(int var6 = 0; var6 < var5; ++var6) {
String alias = var4[var6];
registry.registerAlias(beanName, alias);
}
}
}
4.3详细注册过程
检查是否有同名的BeanDefinition已经在IoC容器中,
如果有同名BeanDefinition,但又不允许覆盖,那么会抛出异常
把Bean的名字存入到beanDifinitionNames的同时
把beanName作为Map的key
把BeanDefinition作为value
存入到IoC容器持有的beanDefinitionMap中去
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition)beanDefinition).validate();
} catch (BeanDefinitionValidationException var8) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8);
}
}
// 检查是否有同名的BeanDefinition已经在IoC容器中,
// 如果有同名BeanDefinition,但又不允许覆盖,那么会抛出异常
BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!this.isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
if (existingDefinition.getRole() < beanDefinition.getRole()) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
}
} else if (!beanDefinition.equals(existingDefinition)) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
}
} else if (this.logger.isTraceEnabled()) {
this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
}
this.beanDefinitionMap.put(beanName, beanDefinition);
} else {
if (this.hasBeanCreationStarted()) {
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;
this.removeManualSingletonName(beanName);
}
} else {
// 这是正常注册BeanDefinition的过程,
// 把Bean的名字存入到beanDifinitionNames的同时,
// 把beanName作为Map的key,
//把BeanDefinition作为value存入到IoC容器持有的beanDefinitionMap中去
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition == null && !this.containsSingleton(beanName)) {
if (this.isConfigurationFrozen()) {
this.clearByTypeCache();
}
} else {
this.resetBeanDefinition(beanName);
}
}