Spring IOC 核心在於「依賴關係的獲取被反轉」:將物件創建與依賴管理從業務代碼剝離,交由容器統一負責。本文追蹤 FileSystemXmlApplicationContext 啟動流程,詳細解析 refresh() 模板方法、XmlBeanDefinitionReader 解析 XML、DefaultListableBeanFactory 註冊 BeanDefinition 的完整鏈路,並附關鍵原始碼片段。
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);
}
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
}
}
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); }
DefaultListableBeanFactory bf = createBeanFactory();
bf.setSerializationId(getId());
customizeBeanFactory(bf);
loadBeanDefinitions(bf); // 關鍵:委派給子類載入 BeanDefinition
this.beanFactory = bf;
}
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); // 讀取配置位置
}
classpath*: 前綴 → 掃描所有 ClassPath 下匹配資源。file: → 解析為檔案系統路徑,FileSystemXmlApplicationContext 覆寫 getResourceByPath() 返回 FileSystemResource。protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) {
Document doc = doLoadDocument(inputSource, resource); // JAXP 解析為 DOM Document
return registerBeanDefinitions(doc, resource); // 轉換為 BeanDefinition
}
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);
}
}
id/name 屬性決定 Bean 名稱與別名。class、scope、lazy-init、factory-method 等屬性構建 AbstractBeanDefinition。<property>、<constructor-arg>、<lookup-method> 等子元素,填充 PropertyValues、ConstructorArgumentValues。BeanDefinitionHolder(包裝 BeanDefinition、名稱、別名)。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 ( 細節解析)
refresh() 模板方法定義骨架,子類實現資源載入差異。BeanDefinition 物件模型 → 註冊至 DefaultListableBeanFactory。BeanFactoryPostProcessor、BeanPostProcessor、自定義命名空間、FactoryBean 等。閱讀原始碼能幫助理解 Spring 行為邊界,排查「Bean 未註冊」「循環依賴」「屬性未注入」等疑難雜症。