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

Spring IOC 容器原始碼深度解析:從 XML 解析到 BeanDefinition 註冊

     編輯:Java 綜合教學

Spring IOC 容器原始碼深度解析:從 XML 解析到 BeanDefinition 註冊

Spring IOC 核心在於「依賴關係的獲取被反轉」:將物件創建與依賴管理從業務代碼剝離,交由容器統一負責。本文追蹤 FileSystemXmlApplicationContext 啟動流程,詳細解析 refresh() 模板方法、XmlBeanDefinitionReader 解析 XML、DefaultListableBeanFactory 註冊 BeanDefinition 的完整鏈路,並附關鍵原始碼片段。

核心介面:BeanFactory

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, Class<T> requiredType);
    <T> T getBean(Class<T> requiredType);
    boolean containsBean(String name);
    boolean isSingleton(String name);
    boolean isPrototype(String name);
    Class<?> getType(String name);
    String[] getAliases(String name);
}

啟動入口:AbstractApplicationContext.refresh()

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        prepareRefresh();                          // 1. 準備上下文環境
        ConfigurableListableBeanFactory bf = obtainFreshBeanFactory(); // 2. 建立/刷新 BeanFactory
        prepareBeanFactory(bf);                    // 3. 配置 BeanFactory 標準屬性
        postProcessBeanFactory(bf);                // 4. 子類擴充點:BeanFactoryPostProcessor
        invokeBeanFactoryPostProcessors(bf);       // 5. 執行 BeanFactoryPostProcessor
        registerBeanPostProcessors(bf);            // 6. 註冊 BeanPostProcessor
        initMessageSource();                       // 7. 國際化
        initApplicationEventMulticaster();         // 8. 事件廣播器
        onRefresh();                               // 9. 子類特殊 Bean 初始化
        registerListeners();                       // 10. 註冊監聽器
        finishBeanFactoryInitialization(bf);       // 11. 實例化所有非懶加載單例
        finishRefresh();                           // 12. 發布 ContextRefreshedEvent
    }
}

建立 BeanFactory:AbstractRefreshableApplicationContext.refreshBeanFactory()

protected final void refreshBeanFactory() throws BeansException {
    if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); }
    DefaultListableBeanFactory bf = createBeanFactory();
    bf.setSerializationId(getId());
    customizeBeanFactory(bf);
    loadBeanDefinitions(bf); // 關鍵:委派給子類載入 BeanDefinition
    this.beanFactory = bf;
}

XML 解析鏈路:AbstractXmlApplicationContext.loadBeanDefinitions()

protected void loadBeanDefinitions(DefaultListableBeanFactory bf) {
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf);
    reader.setEnvironment(getEnvironment());
    reader.setResourceLoader(this);
    reader.setEntityResolver(new ResourceEntityResolver(this));
    initBeanDefinitionReader(reader);
    loadBeanDefinitions(reader); // 讀取配置位置
}

資源定位:PathMatchingResourcePatternResolver.getResources()

  • classpath*: 前綴 → 掃描所有 ClassPath 下匹配資源。
  • 無前綴或 file: → 解析為檔案系統路徑,FileSystemXmlApplicationContext 覆寫 getResourceByPath() 返回 FileSystemResource。

XML 文件解析:XmlBeanDefinitionReader.doLoadBeanDefinitions()

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) {
    Document doc = doLoadDocument(inputSource, resource); // JAXP 解析為 DOM Document
    return registerBeanDefinitions(doc, resource);        // 轉換為 BeanDefinition
}

DOM 轉 BeanDefinition:DefaultBeanDefinitionDocumentReader.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);
    }
}

解析核心:BeanDefinitionParserDelegate.parseBeanDefinitionElement()

  1. 讀取 id/name 屬性決定 Bean 名稱與別名。
  2. 解析 class、scope、lazy-init、factory-method 等屬性構建 AbstractBeanDefinition。
  3. 遞歸解析 <property>、<constructor-arg>、<lookup-method> 等子元素,填充 PropertyValues、ConstructorArgumentValues。
  4. 返回 BeanDefinitionHolder(包裝 BeanDefinition、名稱、別名)。

註冊到容器:DefaultListableBeanFactory.registerBeanDefinition()

public void registerBeanDefinition(String beanName, BeanDefinition bd) {
    // 校驗、覆蓋策略、同步控制
    this.beanDefinitionMap.put(beanName, bd);
    this.beanDefinitionNames.add(beanName);
    this.manualSingletonNames.remove(beanName);
    this.frozenBeanDefinitionNames = null;
    resetBeanDefinition(beanName); // 清除快取
}

至此,beanDefinitionMap : ConcurrentHashMap<String, BeanDefinition> 建立完成,後續 getBean() 依此進行實例化、依賴注入、生命週期管理。

關鍵類關係圖

FileSystemXmlApplicationContext
    → AbstractXmlApplicationContext
        → AbstractRefreshableApplicationContext
            → AbstractApplicationContext (refresh() 模板方法)
                → DefaultListableBeanFactory (BeanDefinition 註冊表)
                → XmlBeanDefinitionReader (XML 解析)
                    → DefaultBeanDefinitionDocumentReader (DOM 轉 BeanDefinition)
                        → BeanDefinitionParserDelegate ( 細節解析)

總結

  1. IOC 核心:將依賴管理提取為獨立容器,實現業務與基礎設施解耦。
  2. 啟動流程:refresh() 模板方法定義骨架,子類實現資源載入差異。
  3. XML 解析:DOM 解析 → BeanDefinition 物件模型 → 註冊至 DefaultListableBeanFactory。
  4. 擴充點:BeanFactoryPostProcessor、BeanPostProcessor、自定義命名空間、FactoryBean 等。

閱讀原始碼能幫助理解 Spring 行為邊界,排查「Bean 未註冊」「循環依賴」「屬性未注入」等疑難雜症。

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