【挑战 Spring】—– Spring IOC 源码调试三之loadBeanDefinitions

前言

当你凝视黑夜的时候,黑夜也在凝视着你!日日当精进,干就完了!上篇Spring IOC 源码调试二的进度,进行到了重点的AbstractBeanDefinitionReaderloadBeanDefinitions方法**,那这一篇接着进行。原创纯手打!实属不易!求赞!求关注!我不会因为您的不支持而低迷,但是有了您的支持我会变的亢奋!

项目结构

这是调试代码

调试代码

开始调试

(重点)1.执行AbstractBeanDefinitionReaderloadBeanDefinitions(String location, @Nullable Set actualResources)

该方法中主要操作有:

  1. ResourceLoader resourceLoader = getResourceLoader():获取一个ResourceLoader(资源加载器)对象

    此时获取到的ResourceLoader具体实现类是ClassPathXmlApplicationContext对象,详情请看Spring IOC 源码调试二2-5部分的第3个操作。

  2. int count = loadBeanDefinitions(resources):继续调用XmlBeanDefinitionReaderloadBeanDefinitions(Resource... resources)方法。此时的this对象是XmlBeanDefinitionReader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
//初始化 XmlBeanDefinitionReader 时 设置了 setResourceLoader(this)
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
// 进一步调用 XmlBeanDefinitionReader的loadBeanDefinitions(Resource... resources)方法
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
return count;
}
}

(重点)2.执行XmlBeanDefinitionReaderloadBeanDefinitions(Resource... resources)方法

看下面代码,该方法中是对每个资源逐一解析的,但是返回值是总的bean的个数。很无奈又是层层调用XmlBeanDefinitionReaderloadBeanDefinitions重载方法,调用过程中有一个逻辑是把参数Resource对象转换成了EncodeResource对象,并且最后调用到XmlBeanDefinitionReaderloadBeanDefinitions(EncodedResource encodedResource)方法

1
2
3
4
5
6
7
8
9
10
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
for (Resource resource : resources) {
// 加载每个资源的 bean 的个数
count += loadBeanDefinitions(resource);
}
// 返回总共 bean 的个数
return count;
}

3.执行XmlBeanDefinitionReaderloadBeanDefinitions(EncodedResource encodedResource)方法

这个方法主要作用我认为就是获取到资源的输入流。重点是将输入流作为参数传入XmlBeanDefinitionReaderdoLoadBeanDefinitions(InputSource inputSource, Resource resource)方法中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}

Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
// 得到资源的输入流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 真正 解析 XML 文件方法
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}

4.(重点中的重点)执行XmlBeanDefinitionReaderdoLoadBeanDefinitions(InputSource inputSource, Resource resource)方法

该方法主要就两个操作:

  1. Document doc = doLoadDocument(inputSource, resource);:将xml文件解析为Document对象
  2. int count = registerBeanDefinitions(doc, resource):注册Beandefinition到容器(DefaultListableBeanFatory)中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**将 xml文件  装载为  BeanDefinition
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {

try {
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}

4-1Document doc = doLoadDocument(inputSource, resource)

此时的this对象依然为XmlBeanDefinitionReader对象,所以会执行XmlBeanDefinitionReaderdoLoadDocument(InputSource inputSource, Resource resource)方法,代码如下:

1
2
3
4
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}

代码执行的逻辑:

  1. 首先在XmlBeanDefinitionReader对象中维护了一个private DocumentLoader documentLoader = new DefaultDocumentLoader();属性
  2. 执行DefaultDocumentLoaderloadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware)方法
  3. 最后调用到DocumentBuilderImplparse(InputSource is)方法,最后执行DOM解析,返回Document对象
  4. 由于DOM解析不是重点此处不进行深度跟踪。

得到xml文件的Document对象后作为参数传给:XmlBeanDefinitionReader对象的registerBeanDefinitions(doc, resource)方法

4-2执行:XmlBeanDefinitionReader对象的registerBeanDefinitions(Document doc, Resource resource)方法

1
2
3
4
5
6
7
8
9
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 获取一个`DefaultBeanDefinitionDocumentReader`对象
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 获取 注册Beandefinition之前 Beandefinition的数量
int countBefore = getRegistry().getBeanDefinitionCount();
// 注册 BeanDefinition
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}

该方法中主要逻辑有:

4-2-1BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader()得到一个BeanDefinitionDocumentReader对象,真正的实现类是DefaultBeanDefinitionDocumentReader
4-2-2int countBefore = getRegistry().getBeanDefinitionCount();:获取 注册Beandefinition之前 Beandefinition的数量
  • 此时this对象为:XmlBeanDefinitionReader对象,调用getRegistry()方法时是调用父类AbstractBeanDefinitionReadergetRegistry()方法。
  • Spring IOC 源码调试二2-5部分的第一个操作在实例化:XmlBeanDefinitionReader对象的时候把DefaultListableBeanFactory最为参数传给了:XmlBeanDefinitionReader的构造参数,而DefaultListableBeanFactory对象又实现了BeanDefinitionRegistry,所以调用AbstractBeanDefinitionReadergetRegistry()方法得到的对象是DefaultListableBeanFactory
  • DefaultListableBeanFactorygetBeanDefinitionCount()方法就是获取beanDefinitionMap(Bean元数据信息集合)中的个数
4-2-3 documentReader.registerBeanDefinitions(doc, createReaderContext(resource));:注册 BeanDefinition
4-2-3.1该方法中参数中有一个逻辑:createReaderContext(resource):我理解为构造:XmlBeanDefinitionReader对象的应用上下文

大概意思就是把:XmlBeanDefinitionReader包装一下变成XmlReaderContext对象

1
2
3
4
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
4-2-3.2 (this对象变化)进入到DefaultBeanDefinitionDocumentReaderregisterBeanDefinitions(Document doc, XmlReaderContext readerContext)方法

此时的this对象变为了DefaultBeanDefinitionDocumentReader

看到下面代码就知道三个操作

  • this.readerContext = readerContext;:将上层函数传进来的XmlReaderContext赋值给自己的属性
  • doc.getDocumentElement()获取Document的节点对象
  • 调用DefaultBeanDefinitionDocumentReaderdoRegisterBeanDefinitions(Element root)方法
1
2
3
4
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
4-2-3.3 执行DefaultBeanDefinitionDocumentReaderdoRegisterBeanDefinitions(Element root)方法

该方法注释翻译过来是:在给定的根中注册每个bean定义,我理解就是……好吧我没理解啥。

主要有两个操作

  • this.delegate = createDelegate(getReaderContext(), root, parent);:获取 BeanDefinitionParserDelegate 对象

    简单说一下BeanDefinitionParserDelegate 对象:

    1. 里面维护了Spring的xml配置文的标签常量。(比如 “bean”、”name”、“id”、”singleton”、”scope”)
    2. 里面封装了将标签解析为Beandefinition的方法
  • parseBeanDefinitions(root, this.delegate);:一看这方法就知道后面将注册又委托给了this.delegate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**在给定的根中注册每个bean定义
* Register each bean definition within the given root {@code <beans/>} element.
*/
@SuppressWarnings("deprecation") // for Environment.acceptsProfiles(String...)
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
// 获取 BeanDefinitionParserDelegate 对象
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
// 空方法
preProcessXml(root);
// 解析xml 标签
parseBeanDefinitions(root, this.delegate);
// 空方法
postProcessXml(root);
this.delegate = parent;
}
4-2-3.4 进入到DefaultBeanDefinitionDocumentReaderparseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法

在该方法中,要了解一下Dom解析相关的 Node、Element等对象

因为要解析我们在xml中配置的Bean,所以会parseDefaultElement(ele, delegate)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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)) {
// 只 解析 "import", "alias", "bean", "beans" 标签
parseDefaultElement(ele, delegate);
}
else {
// 解析 其他的标签 比如 <component-scan> 标签
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
4-2-3.5 进入到DefaultBeanDefinitionDocumentReaderparseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)方法

因为调试项目中只配置了<bean></bean>标签,所以只关注代码中的processBeanDefinition(ele, delegate);方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
// 解析 bean 标签
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
4-2-3.6 (this对象变化)进入到DefaultBeanDefinitionDocumentReader的processBeanDefinition(ele, delegate);方法

看代码了解到,将解析任务委托给了BeanDefinitionParserDelegate 对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 将 xml 配置信息封装为 Beandefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//将 Beandefinition 注册到 容器(DefaultListableBeanFactory) 中
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}

该方法主要的3个操作

  1. BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele):将 xml 配置信息封装为 Beandefinition

    在这段代码中可以得知:

    • xml配置的id属性就是我们Bean的名字
    • 容器中bean的名字是唯一的
    • parseBeanDefinitionElement(ele, beanName, containingBean)方法中还会初始化Beandefinition的一些属性
    • 最后返回BeanDefinitionHolder对象将Beandefinition包装起来
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    String id = ele.getAttribute(ID_ATTRIBUTE);
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

    List<String> aliases = new ArrayList<>();
    if (StringUtils.hasLength(nameAttr)) {
    String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
    aliases.addAll(Arrays.asList(nameArr));
    }
    // 定义 bean 的名字 为xml中配置的 id 属性
    String beanName = id;
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
    beanName = aliases.remove(0);
    if (logger.isTraceEnabled()) {
    logger.trace("No XML 'id' specified - using '" + beanName +
    "' as bean name and " + aliases + " as aliases");
    }
    }
    // 校验名字是不是唯一的
    if (containingBean == null) {
    checkNameUniqueness(beanName, aliases, ele);
    }
    // 将xml配置信息 封装成 BeanDefinition 对象
    AbstractBeanDefinition beanDefinition = 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);
    // Register an alias for the plain bean class name, if still possible,
    // if the generator returned the class name plus a suffix.
    // This is expected for Spring 1.2/2.0 backwards compatibility.
    String beanClassName = beanDefinition.getBeanClassName();
    if (beanClassName != null &&
    beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
    !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
    aliases.add(beanClassName);
    }
    }
    if (logger.isTraceEnabled()) {
    logger.trace("Neither XML 'id' nor 'name' specified - " +
    "using generated bean name [" + beanName + "]");
    }
    }
    catch (Exception ex) {
    error(ex.getMessage(), ele);
    return null;
    }
    }
    String[] aliasesArray = StringUtils.toStringArray(aliases);
    return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }

    return null;
    }
  2. 注册Beandefinition到容器中:BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

    • getReaderContext().getRegistry():因为在4-2-3.1中封装的XmlReaderContext对象包含:XmlBeanDefinitionReader对象的所有信息,所以这个方法获取到的对象就是容器对象DefaultListableBeanFactory

    • 该方法将第一个操作获取到的bdHolderBeandefinition对象的持有者)和 容器对象作为参数传入

    • 进入方法后又调用registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())(此时registry就是DefaultListableBeanFactory对象)将Beandefinition对象添加到DefaultListableBeanFactory对象的属性Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256)中,就算注册完成了

    • BeanDefinitionReaderUtilsregisterBeanDefinition()方法代码

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

      // Register bean definition under primary name.
      String beanName = definitionHolder.getBeanName();
      // 调用 容器对象(DefaultListableBeanFactory) 注册 Beandefinition
      registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
      // Register aliases for bean name, if any.
      String[] aliases = definitionHolder.getAliases();
      if (aliases != null) {
      for (String alias : aliases) {
      registry.registerAlias(beanName, alias);
      }
      }
      }
    • registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

      该方法中还有一些逻辑,但是主流程就是将Beandefinition添加到beanDefinitionMap

  3. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder))

    该方法注释为Send registration event,我理解是发布一个注册事件。这块没有深入跟踪。

4-2-3.7回到DefaultBeanDefinitionDocumentReaderparseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)方法(4-2-3.5)

此时processBeanDefinition(ele, delegate);方法执行完毕

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
4-2-3.8回到DefaultBeanDefinitionDocumentReaderparseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法(4-2-3.4)

此时 parseDefaultElement(ele, delegate);方法执行完毕,但是此处是遍历根节点对象,意思就是多个<bean></bean>标签的话就会遍历执行解析重复上面的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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)) {
// 只 解析 "import", "alias", "bean", "beans" 标签
parseDefaultElement(ele, delegate);
}
else {
// 解析 其他的标签 比如 <component-scan> 标签
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
4-2-3.9回到DefaultBeanDefinitionDocumentReaderdoRegisterBeanDefinitions(Element root)方法(4-2-3.3)
  • 此时执行完了parseBeanDefinitions(root, this.delegate);方法
  • 执行this.delegate = parent,即将this.delegate置为null
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
//得到一个 BeanDefinitionParserDelegate 对象
this.delegate = createDelegate(getReaderContext(), root, parent);

if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
// 空方法
preProcessXml(root);
// 解析xml 标签
parseBeanDefinitions(root, this.delegate);
// 空方法
postProcessXml(root);

this.delegate = parent;
}
4-2-3.10回到DefaultBeanDefinitionDocumentReaderregisterBeanDefinitions(Document doc, XmlReaderContext readerContext)方法(4-2-3.2)

此时执行完了doRegisterBeanDefinitions(doc.getDocumentElement());方法

1
2
3
4
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
4-2-4回到XmlBeanDefinitionReader对象的registerBeanDefinitions(Document doc, Resource resource)方法(4-2)
  • 此时执行完了documentReader.registerBeanDefinitions(doc, createReaderContext(resource));方法
  • 执行getRegistry().getBeanDefinitionCount() - countBefore计算得出该次注册BeanDefinition的个数
1
2
3
4
5
6
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
4-2-5 回到XmlBeanDefinitionReaderdoLoadBeanDefinitions(InputSource inputSource, Resource resource)方法(4)
  • 此时执行完了int count = registerBeanDefinitions(doc, resource);方法
  • 然后将 count 返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**将 xml文件  装载为  BeanDefinition
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {

try {
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}

5 回到本文章开始AbstractBeanDefinitionReaderloadBeanDefinitions(String location, @Nullable Set actualResources)方法(1)

  • 此时执行完了count += loadBeanDefinitions(resource);方法
  • 因为我只配置了一个xml,所以只有一个resource
  • 此处的count为容器中总共Beandefinition的数量
1
2
3
4
5
6
7
8
9
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
for (Resource resource : resources) {
// 加载每个资源的 bean 的个数
count += loadBeanDefinitions(resource);
}
return count;
}

总结

  1. loadBeanDefinitions()方法包含了对xml文件的解析以及对Beandefinition对象的封装和注册
  2. loadBeanDefinitions()中最后注册是调用的DefaultListableBeanFactory对象的方法
  3. 解析出的Beandefinition对象都被维护在DefaultListableBeanFactory对象的Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);属性中
  4. 函数调用太深了,但是有规律可循,基本上就是方法重载和任务委托给其他的类来执行任务,要时刻关注this对象是谁
  5. 该文章并没有面面俱到,尤其是最后注册那一块不够详细,但是主流程还是走通了。

欢迎扫码关注

如果喜欢请关注我公众号【程序倾听者】,说出你的故事!我在这里倾听!

顶我一下下!
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2015-2021 ListenerSun
  • 访问人数: | 浏览次数:

请我吃个棒棒糖可否~

支付宝
微信