首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring BeanFactory 解析 Bean 全流程源碼深度剖析:從 XML 到 BeanDefinition 註冊

     編輯:Java 相關知識

Spring 容器啟動的核心是 **BeanDefinition 的讀取、解析與註冊**。本文以 XmlBeanFactory 為切入點,跟蹤 XmlBeanDefinitionReader → DefaultBeanDefinitionDocumentReader → BeanDefinitionParserDelegate 的完整調用鏈,還原 Spring 如何將 XML `` 轉化為內存中的 BeanDefinition 並註冊到註冊表。

入口:XmlBeanFactory 構造器

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。

讀取流程:loadBeanDefinitions

// XmlBeanDefinitionReader
public int loadBeanDefinitions(Resource resource) {
    return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) {
    // 1. 編碼處理、循環加載檢測
    // 2. 獲取 InputStream → InputSource
    // 3. doLoadBeanDefinitions(inputSource, resource)
}

核心解析:doLoadBeanDefinitions

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) {
    Document doc = doLoadDocument(inputSource, resource); // XML → DOM Document
    return registerBeanDefinitions(doc, resource);        // 解析註冊
}

XML → Document:DefaultDocumentLoader

public Document loadDocument(InputSource inputSource, ...) {
    DocumentBuilderFactory factory = createDocumentBuilderFactory(...);
    DocumentBuilder builder = createDocumentBuilder(factory, ...);
    return builder.parse(inputSource); // JAXP 解析
}

Document → BeanDefinition:registerBeanDefinitions

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;
}

默認文檔讀取器:DefaultBeanDefinitionDocumentReader

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)
}

遞歸解析元素:parseBeanDefinitions

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);
    }
}

關鍵區分:默認命名空間 vs 自定義命名空間

  • 默認:<bean id="x" class="..."/> → parseDefaultElement → BeanDefinitionParserDelegate.parseBeanDefinitionElement
  • 自定義:<tx:annotation-driven/>、<context:component-scan/> → NamespaceHandler 機制處理

總結:核心類職責鏈

類職責
XmlBeanFactory入口,整合 Reader 與 Registry
XmlBeanDefinitionReader資源編碼、InputSource 構建、委派 DocumentLoader
DefaultDocumentLoaderJAXP 解析 XML → DOM Document
DefaultBeanDefinitionDocumentReader遍歷 DOM 樹,協調默認/自定義命名空間解析
BeanDefinitionParserDelegate具體 元素屬性解析、BeanDefinition 構建
DefaultListableBeanFactoryBeanDefinition 註冊表(Map)

理解這條鏈路,能讓你在排查 Bean 加載失敗、自定義命名空間擴展、源碼級 Debug 時游刃有餘。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved