Spring 容器啟動的核心是 **BeanDefinition 的讀取、解析與註冊**。本文以 XmlBeanFactory 為切入點,跟蹤 XmlBeanDefinitionReader → DefaultBeanDefinitionDocumentReader → BeanDefinitionParserDelegate 的完整調用鏈,還原 Spring 如何將 XML `BeanDefinition 並註冊到註冊表。
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parent) throws BeansException {
super(parent);
this.reader.loadBeanDefinitions(resource); // 核心入口
}
}
繼承 DefaultListableBeanFactory(Bean 註冊表默認實現),持有 XmlBeanDefinitionReader 讀取 XML。
// XmlBeanDefinitionReader
public int loadBeanDefinitions(Resource resource) {
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) {
// 1. 編碼處理、循環加載檢測
// 2. 獲取 InputStream → InputSource
// 3. doLoadBeanDefinitions(inputSource, resource)
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) {
Document doc = doLoadDocument(inputSource, resource); // XML → DOM Document
return registerBeanDefinitions(doc, resource); // 解析註冊
}
public Document loadDocument(InputSource inputSource, ...) {
DocumentBuilderFactory factory = createDocumentBuilderFactory(...);
DocumentBuilder builder = createDocumentBuilder(factory, ...);
return builder.parse(inputSource); // JAXP 解析
}
public int registerBeanDefinitions(Document doc, Resource resource) {
BeanDefinitionDocumentReader reader = createBeanDefinitionDocumentReader();
reader.setEnvironment(getEnvironment());
int before = getRegistry().getBeanDefinitionCount();
reader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - before;
}
public void registerBeanDefinitions(Document doc, XmlReaderContext ctx) {
this.readerContext = ctx;
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
// 1. profile 檢查
// 2. preProcessXml(root)
// 3. parseBeanDefinitions(root, delegate) // 核心遞歸解析
// 4. postProcessXml(root)
}
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)) {
parseDefaultElement(ele, delegate); // 等
} else {
delegate.parseCustomElement(ele); // 等自定義命名空間
}
}
}
} else {
delegate.parseCustomElement(root);
}
}
<bean id="x" class="..."/> → parseDefaultElement → BeanDefinitionParserDelegate.parseBeanDefinitionElement<tx:annotation-driven/>、<context:component-scan/> → NamespaceHandler 機制處理| 類 | 職責 |
|---|---|
| XmlBeanFactory | 入口,整合 Reader 與 Registry |
| XmlBeanDefinitionReader | 資源編碼、InputSource 構建、委派 DocumentLoader |
| DefaultDocumentLoader | JAXP 解析 XML → DOM Document |
| DefaultBeanDefinitionDocumentReader | 遍歷 DOM 樹,協調默認/自定義命名空間解析 |
| BeanDefinitionParserDelegate | 具體 |
| DefaultListableBeanFactory | BeanDefinition 註冊表(Map |
理解這條鏈路,能讓你在排查 Bean 加載失敗、自定義命名空間擴展、源碼級 Debug 時游刃有餘。