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

Spring IOC 容器啟動核心流程:Resource 定位與載入機制深度解析

     編輯:Java 綜合教學

Spring IOC 容器啟動核心流程:Resource 定位與載入機制深度解析

Spring IOC 容器啟動分為兩大階段:容器啟動階段(載入/解析配置、註冊 BeanDefinition)與 Bean 實例化階段(建立實例、依賴注入、生命週期管理)。本文聚焦啟動階段的第一步——Resource 定位,追蹤從 ApplicationContext 建構到 ResourceLoader 解析配置路徑的完整呼叫鏈。

一、Resource 抽象與實作體系

Spring 以 org.springframework.core.io.Resource 介面統一抽象各類資源(檔案、Classpath、URL、InputStream 等),主要實作:

  • ClassPathResource:類路徑資源(classpath:xxx.xml)
  • FileSystemResource:檔案系統絕對/相對路徑
  • UrlResource:HTTP、FTP、JAR 等 URL 協定
  • ServletContextResource:Web 應用根目錄下資源
  • InputStreamResource、ByteArrayResource 等

二、FileSystemXmlApplicationContext 啟動流程追蹤

1. 建構子鏈與 refresh() 入口

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) {
    super(parent);
    setConfigLocations(configLocations); // 保存配置路徑陣列
    if (refresh) {
        refresh(); // 啟動容器初始化核心入口
    }
}

AbstractApplicationContext.refresh() 是 IOC 容器初始化的總開關。

2. refreshBeanFactory() → loadBeanDefinitions()

protected final void refreshBeanFactory() {
    // ... 銷毀舊 BeanFactory ...
    DefaultListableBeanFactory beanFactory = createBeanFactory(); // 建立預設 BeanFactory
    beanFactory.setSerializationId(getId());
    customizeBeanFactory(beanFactory);
    loadBeanDefinitions(beanFactory); // 關鍵:載入 BeanDefinition
    this.beanFactory = beanFactory;
}

3. AbstractXmlApplicationContext.loadBeanDefinitions()

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
    reader.setResourceLoader(this); // 關鍵:注入 ResourceLoader(即 ApplicationContext 本身)
    reader.setEntityResolver(new ResourceEntityResolver(this));
    loadBeanDefinitions(reader); // 模板方法,由子類實作
}

4. 取得配置資源:getConfigResources() / getConfigLocations()

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) {
    Resource[] configResources = getConfigResources(); // 直接取得 Resource 陣列
    if (configResources != null) reader.loadBeanDefinitions(configResources);
    String[] configLocations = getConfigLocations(); // 取得路徑字串陣列
    if (configLocations != null) reader.loadBeanDefinitions(configLocations);
}

三、ResourceLoader 解析路徑的核心邏輯

XmlBeanDefinitionReader 繼承 AbstractBeanDefinitionReader,持有 ResourceLoader。載入路徑字串時委派給 ResourceLoader.getResource(String location):

public Resource getResource(String location) {
    if (location.startsWith("/")) {
        return getResourceByPath(location); // 絕對路徑 → 子類實作
    } else if (location.startsWith(CLASSPATH_URL_PREFIX)) { // "classpath:"
        return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
    } else {
        try {
            URL url = new URL(location); // 嘗試解析為 URL
            return new UrlResource(url);
        } catch (MalformedURLException ex) {
            return getResourceByPath(location); // 退回相對路徑處理
        }
    }
}

四、FileSystemXmlApplicationContext 的 getResourceByPath 實作

protected Resource getResourceByPath(String path) {
    if (path != null && path.startsWith("/")) {
        path = path.substring(1); // 移除前導斜線
    }
    return new FileSystemResource(path); // 解析為檔案系統資源
}

因此 FileSystemXmlApplicationContext 專門支援檔案系統絕對/相對路徑(非 classpath)。

五、ResourcePatternResolver 擴展:支援通配符

若 ResourceLoader 實作 ResourcePatternResolver,getResources(String locationPattern) 可解析 classpath*:/META-INF/*-context.xml 等通配符模式,掃描多路徑。

六、完整呼叫鏈總結

  1. new FileSystemXmlApplicationContext("beans.xml")
  2. refresh() → refreshBeanFactory()
  3. createBeanFactory() → DefaultListableBeanFactory
  4. loadBeanDefinitions(beanFactory) → XmlBeanDefinitionReader
  5. reader.loadBeanDefinitions(configLocations)
  6. resourceLoader.getResource(location)(委派 DefaultResourceLoader)
  7. getResourceByPath() → new FileSystemResource(path)
  8. reader.loadBeanDefinitions(resource) → SAX 解析 XML → 註冊 BeanDefinition

七、關鍵設計模式

  • 模板方法:AbstractApplicationContext.refresh() 定義骨架,loadBeanDefinitions() 由子類實作。
  • 策略模式:ResourceLoader/ResourcePatternResolver 封裝不同資源解析策略。
  • 工廠模式:DefaultListableBeanFactory 為 BeanDefinition 註冊表與 Bean 建立工廠。

八、實戰啟示

  • 自訂 ApplicationContext 時,覆寫 getResourceByPath() 即可支援新資源類型。
  • 理解 classpath:、file:、http: 前綴對應的 Resource 實作,避免路徑解析錯誤。
  • refresh() 可多次呼叫(重新載入),但需注意同步與銷毀舊 Bean。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved