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

Spring IOC 容器深度解析:從核心原理到源碼級實現流程

     編輯:Java 相關知識

IOC 本質:控制反轉與依賴注入

IOC (Inversion of Control):將對象創建、依賴管理權從應用代碼「反轉」給容器。
DI (Dependency Injection):容器在創建 Bean 時,自動將依賴注入到目標對象(構造器/Setter/字段)。

IOC 容器啟動全流程(源碼級)

┌─────────────────────────────────────────────────────────────────────────────┐
│                        Spring IOC 容器啟動階段                               │
├─────────────────────────────────────────────────────────────────────────────┤
│  1. Resource Loading        →  加載配置元數據 (XML/Annotation/JavaConfig)    │
│  2. BeanDefinition Parsing  →  解析為 BeanDefinition (內部元數據模型)       │
│  3. BeanDefinition Registry →  註冊到 BeanDefinitionRegistry (Map 結構)     │
│  4. BeanFactoryPostProcessor→  後處理器修改 BeanDefinition (如 PropertyPlaceholderConfigurer) │
└─────────────────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────────────────┐
│                        Bean 實例化階段                                       │
├─────────────────────────────────────────────────────────────────────────────┤
│  1. Instantiation           →  反射/CGLIB 創建 Bean 實例                    │
│  2. Property Population     →  依賴注入 (Setter/構造器/字段)                │
│  3. BeanPostProcessor       →  前/後置處理 (如 @Autowired, AOP 代理創建)    │
│  4. Initialization          →  @PostConstruct, InitializingBean, init-method│
│  5. Ready for Use           →  放入單例池 (singletonObjects)                │
└─────────────────────────────────────────────────────────────────────────────┘

核心組件架構

組件核心接口/類職責
資源加載 Resource, ResourceLoader 統一抽象配置文件來源 (classpath、文件系統、URL)
解析引擎 BeanDefinitionReader (XmlBeanDefinitionReader 等) 將 XML/註解轉為 BeanDefinition
註冊表 BeanDefinitionRegistry (DefaultListableBeanFactory) 存儲 beanName → BeanDefinition 映射
後處理器 BeanFactoryPostProcessor, BeanPostProcessor 擴展點:修改定義 / 包裝實例 (AOP、@Autowired 實現)
實例化策略 InstantiationStrategy (CglibSubclassing / Simple) 反射或字節碼生成創建實例
屬性填充 BeanWrapper, PropertyValues 統一屬性訪問,支援類型轉換、嵌套路徑

手寫迷你 IOC 容器:理解核心原理

// 1. BeanDefinition 元數據模型
public class BeanDefinition {
    private String beanClassName;
    private boolean singleton = true;
    private boolean lazyInit = false;
    private PropertyValues propertyValues; // 依賴屬性
    // getter/setter 省略
}

// 2. 簡易 BeanFactory
public class SimpleBeanFactory implements BeanFactory {
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    
    public void registerBeanDefinition(String name, BeanDefinition bd) {
        beanDefinitionMap.put(name, bd);
    }
    
    @Override
    public Object getBean(String name) {
        // 單例檢查
        Object singleton = singletonObjects.get(name);
        if (singleton != null) return singleton;
        
        BeanDefinition bd = beanDefinitionMap.get(name);
        if (bd == null) throw new NoSuchBeanDefinitionException(name);
        
        // 實例化
        Object bean = createBean(bd);
        
        // 依賴注入
        populateBean(bean, bd.getPropertyValues());
        
        // 初始化回調
        initializeBean(bean, name);
        
        // 註冊單例
        if (bd.isSingleton()) singletonObjects.put(name, bean);
        return bean;
    }
    
    private Object createBean(BeanDefinition bd) {
        try {
            Class<?> clazz = Class.forName(bd.getBeanClassName());
            return clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) { throw new BeanCreationException(e); }
    }
    
    private void populateBean(Object bean, PropertyValues pvs) {
        // 簡化:遍歷 PropertyValues 反射設置屬性
        for (PropertyValue pv : pvs.getPropertyValues()) {
            try {
                Field field = bean.getClass().getDeclaredField(pv.getName());
                field.setAccessible(true);
                field.set(bean, pv.getValue());
            } catch (Exception e) { throw new BeanCreationException(e); }
        }
    }
    
    private void initializeBean(Object bean, String name) {
        // 支援 InitializingBean / @PostConstruct / init-method
        if (bean instanceof InitializingBean) {
            ((InitializingBean) bean).afterPropertiesSet();
        }
        // ... 其他初始化邏輯
    }
}

關鍵擴展點深度解析

1. BeanFactoryPostProcessor:修改 BeanDefinition

// 典型應用:PropertyPlaceholderConfigurer 解析 ${xxx}
public class PropertyPlaceholderConfigurer implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) {
        // 遍歷所有 BeanDefinition,替換屬性值中的 ${key} 為 properties 文件值
    }
}

2. BeanPostProcessor:包裝/代理 Bean 實例

// 核心應用:AutowiredAnnotationBeanPostProcessor、AOP 代理創建
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String name) {
        // 初始化前:如處理 @Autowired 注入
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String name) {
        // 初始化後:如創建 AOP 代理
        if (needProxy(bean)) return Proxy.newProxyInstance(...);
        return bean;
    }
}

3. FactoryBean:封裝複雜對象創建邏輯

// 用戶實現 FactoryBean,getObject() 返回真實對象
public class DataSourceFactoryBean implements FactoryBean<DataSource> {
    private String url, username, password;
    
    @Override
    public DataSource getObject() {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl(url); ds.setUsername(username); ds.setPassword(password);
        return ds;
    }
    
    @Override public Class<?> getObjectType() { return DataSource.class; }
    @Override public boolean isSingleton() { return true; }
}

循環依賴解決方案:三級緩存機制

┌────────────────────────────────────────────────────────────┐
│  DefaultSingletonBeanRegistry 三級緩存                      │
├────────────────────────────────────────────────────────────┤
│  singletonObjects      →  完全初始化好的單例 Bean           │
│  earlySingletonObjects →  早期暴露的單例 Bean (實例化後、屬性填充前) │
│  singletonFactories    →  ObjectFactory (創建早期引用的工廠)  │
└────────────────────────────────────────────────────────────┘

流程:
A 依賴 B,B 依賴 A
1. A 實例化 → 放入 singletonFactories (ObjectFactory)
2. A 屬性填充需 B → getBean(B)
3. B 實例化 → 放入 singletonFactories
4. B 屬性填充需 A → getBean(A) → 從 singletonFactories 獲取 ObjectFactory → getObject() 返回早期 A 引用 → 放入 earlySingletonObjects
5. B 完成初始化 → 移至 singletonObjects
6. A 繼續填充屬性 (已獲取 B) → 完成初始化 → 移至 singletonObjects
僅支援 Setter/字段注入 的循環依賴。構造器注入循環依賴無法解決(需打破循環或使用 @Lazy)。

總結

Spring IOC 容器以 BeanDefinition 為核心元數據模型,通過 資源加載 → 解析註冊 → 後處理增強 → 實例化 → 依賴注入 → 初始化 → 緩存 的標準化流程,構建了極具擴展性的對象管理體系。理解其源碼級實現,不僅能排查疑難雜症(循環依賴、Bean 不生效、AOP 失效),更能在框架設計、中間件開發中復用其精妙的擴展點機制。

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