BeanDefinition 的加载与注册

回顾之前

我们看到 refresh() 方法的执行步骤,其中 第 2 步:obtainFreshBeanFactory() 很关键。
它会:

  1. 创建 BeanFactory

  2. 加载并解析配置文件(比如 XML)

  3. 把解析结果放到 BeanFactory 里

关键类:XmlBeanDefinitionReader

在 ClassPathXmlApplicationContext 里,加载配置的逻辑大致是:

1
2
3
4
5
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 解析 application.xml
beanDefinitionReader.loadBeanDefinitions(configResources);
}

XmlBeanDefinitionReader 的任务:

  • 读取 XML 文件
  • 标签解析成 BeanDefinition 对象
  • 注册到 BeanDefinitionRegistry(其实就是 BeanFactory)

什么是 BeanDefinition?

Spring 用 BeanDefinition 来保存 Bean 的元信息:
比如:

1
2

<bean id="myService" class="com.example.MyService"/>

会解析成类似结构:

1
2
3
4
5
6
7
BeanDefinition {
beanClass = "com.example.MyService"
scope = "singleton"
lazyInit = false
constructorArgs = []
propertyValues = []
}

加载流程源码

在 XmlBeanDefinitionReader 里核心方法是:

1
2
3
4
5
6
7
8
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
try (InputStream inputStream = resource.getInputStream()) {
// 把 XML 解析成 Document
Document doc = doLoadDocument(inputStream, resource);
// 解析 Document,得到 BeanDefinition
return registerBeanDefinitions(doc, resource);
}
}

关键调用链:

  1. doLoadDocument → 用 DocumentLoader 把 XML 文件读成 DOM
  2. registerBeanDefinitions → 用 BeanDefinitionDocumentReader 解析 DOM
  3. parseBeanDefinitionElement → 遇到 <bean> 标签时,解析成 BeanDefinition
  4. registry.registerBeanDefinition → 存入 DefaultListableBeanFactory 的 Map

BeanDefinition 注册

最终会走到 DefaultListableBeanFactory 的方法:

1
2
3
4
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
this.beanDefinitionMap.put(beanName, beanDefinition);
}

📌 这一步就把 配置文件里的 bean -> BeanDefinition 对象 存到 beanDefinitionMap 里。
后续实例化 Bean 时,就会从这里读取定义。

调试建议

  1. XmlBeanDefinitionReader#loadBeanDefinitions 打断点
  2. doc(Document 对象)里是不是能看到 <bean> 节点
  3. 进入 BeanDefinitionParserDelegate#parseBeanDefinitionElement,观察是如何读取 idclass
  4. 最后在 DefaultListableBeanFactory#registerBeanDefinition 看 Map 里多了 myService