| 實現類 | 適用場景 | 構造示例 |
| ClassPathResource | 類路徑資源 | new ClassPathResource("beans.xml") |
| FileSystemResource | 文件系統絕對/相對路徑 | new FileSystemResource("/etc/config/beans.xml") |
| UrlResource | HTTP/FTP/JAR URL | new UrlResource("https://example.com/beans.xml") |
| InputStreamResource | 輸入流包裝 | new InputStreamResource(inputStream) |
| ByteArrayResource | 字節數組 | new ByteArrayResource(bytes) |
所有實現均提供 getInputStream()、exists()、getFilename()、getDescription() 等統一訪問接口。
XmlBeanDefinitionReader.loadBeanDefinitions() 解析入口
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource)); // 包裝編碼信息
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) inputSource.setEncoding(encodedResource.getEncoding());
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} finally {
inputStream.close();
}
}
職責:資源 → InputStream → InputSource(SAX/DOM 通用輸入源),處理編碼,委託 doLoadBeanDefinitions()。
doLoadBeanDefinitions():DOM 解析與註冊分發
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
int validationMode = getValidationModeForResource(resource); // DTD/XSD 驗證模式
Document doc = documentLoader.loadDocument(inputSource, entityResolver, errorHandler, validationMode, namespaceAware);
return registerBeanDefinitions(doc, resource); // 委託註冊
} catch (Exception ex) {
throw new BeanDefinitionStoreException("Failed to load bean definitions from " + resource, ex);
}
}
關鍵組件:
DefaultDocumentLoader:使用 JAXP DocumentBuilderFactory 解析 XML 為 DOM Document。
ResourceEntityResolver:解析 Spring DTD/XSD(支援 classpath: 协议)。
registerBeanDefinitions(Document, Resource):分發到具體解析器。
registerBeanDefinitions():解析器策略模式
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 老版本支援自定義 parserClass(默認 DefaultXmlBeanDefinitionParser)
if (this.parserClass != null) {
XmlBeanDefinitionParser parser = (XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);
return parser.registerBeanDefinitions(this, doc, resource);
}
// 現代版本:BeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getBeanFactory().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getBeanFactory().getBeanDefinitionCount() - countBefore;
}
演進:早期 XmlBeanDefinitionParser 接口 → 現代 BeanDefinitionDocumentReader(默認 DefaultBeanDefinitionDocumentReader)。
DefaultBeanDefinitionDocumentReader:遞歸解析 元素
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
Element root = doc.getDocumentElement();
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
preProcessXml(root);
parseBeanDefinitions(root, delegate); // 核心遞歸入口
postProcessXml(root);
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root.getNamespaceURI())) {
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.getNamespaceURI())) {
parseDefaultElement(ele, delegate); // 默認命名空間:、、
} else {
delegate.parseCustomElement(ele); // 擴展命名空間:、、
}
}
}
} else {
delegate.parseCustomElement(root);
}
}
parseDefaultElement():三大核心元素處理
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT)) { //
importBeanDefinitionResource(ele);
} else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT)) { //
String name = ele.getAttribute(NAME_ATTRIBUTE);
String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
getReaderContext().getReader().getBeanFactory().registerAlias(name, alias);
getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
} else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) { //
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); // 處理 、 等
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
}
BeanDefinitionParserDelegate.parseBeanDefinitionElement(): 完整解析
解析屬性並構建 GenericBeanDefinition(或 RootBeanDefinition/ChildBeanDefinition):
- 標識:
id、name(別名)、alias。
- 類信息:
class、parent(繼承 BeanDefinition)。
- 作用域:
scope(singleton/prototype/request/session/自定義)。
- 懶加載:
lazy-init。
- 依賴注入模式:
autowire(no/byName/byType/constructor)、autowire-candidate。
- 依賴關係:
depends-on(初始化順序)、factory-bean/factory-method(工廠方法)。
- 構造函數參數:
<constructor-arg>(索引、類型、名稱、值/引用)。
- 屬性注入:
<property>(名稱、值/引用/列表/Map/Set/Props)。
- 生命週期:
init-method、destroy-method。
- 方法覆蓋/查找:
<lookup-method>、<replaced-method>(方法注入)。
- 元數據:
<meta>、<qualifier>(自動裝配限定符)。
解析完成返回 BeanDefinitionHolder(beanName + BeanDefinition + aliases)。
BeanDefinitionReaderUtils.registerBeanDefinition():註冊到註冊表
public static void registerBeanDefinition(BeanDefinitionHolder bdHolder, BeanDefinitionRegistry registry) {
String beanName = bdHolder.getBeanName();
registry.registerBeanDefinition(beanName, bdHolder.getBeanDefinition());
String[] aliases = bdHolder.getAliases();
if (aliases != null) for (String alias : aliases) registry.registerAlias(beanName, alias);
}
DefaultListableBeanFactory.registerBeanDefinition():Map 存儲與驗證
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
// 1. 驗證 BeanDefinition
validateBeanDefinition(beanName, beanDefinition);
// 2. 處理覆蓋
BeanDefinition existing = beanDefinitionMap.get(beanName);
if (existing != null) {
if (!allowBeanDefinitionOverriding) throw new BeanDefinitionOverrideException(beanName);
if (existing.getRole() < beanDefinition.getRole()) return; // 框架 Bean 優先
} else {
beanDefinitionNames.add(beanName); // 記錄註冊順序
}
// 3. 存入 Map
beanDefinitionMap.put(beanName, beanDefinition);
// 4. 清理單例緩存(若已提前實例化)
removeSingleton(beanName);
}
完整調用鏈總結(文本版)
new XmlBeanFactory(resource)
↓
super(parentBeanFactory) → DefaultListableBeanFactory 初始化
↓
reader.loadBeanDefinitions(resource)
├─ loadBeanDefinitions(EncodedResource)
│ ├─ resource.getInputStream() → InputStream
│ ├─ new InputSource(inputStream) → InputSource
│ └─ doLoadBeanDefinitions(inputSource, resource)
│ ├─ documentLoader.loadDocument() → DOM Document
│ └─ registerBeanDefinitions(doc, resource)
│ ├─ createBeanDefinitionDocumentReader() → DefaultBeanDefinitionDocumentReader
│ ├─ documentReader.registerBeanDefinitions(doc, readerContext)
│ │ ├─ parseBeanDefinitions(root, delegate)
│ │ │ ├─ parseDefaultElement(ele, delegate)
│ │ │ │ ├─ → importBeanDefinitionResource() → 遞歸載入
│ │ │ │ ├─ → registerAlias()
│ │ │ │ └─ → delegate.parseBeanDefinitionElement() → BeanDefinitionHolder
│ │ │ │ ├─ 解析所有屬性、子元素
│ │ │ │ ├─ decorateBeanDefinitionIfRequired() → 處理 qualifier/meta
│ │ │ │ └─ BeanDefinitionReaderUtils.registerBeanDefinition()
│ │ │ │ └─ registry.registerBeanDefinition() → beanDefinitionMap.put()
│ │ │ └─ 自定義命名空間 → delegate.parseCustomElement()
│ │ └─ 返回註冊數量
│ └─ 返回註冊數量
└─ 返回註冊數量
XmlBeanFactory vs ApplicationContext 核心差異
| 特性 | XmlBeanFactory | ApplicationContext |
| BeanDefinition 載入時機 | 構造函數中立即載入 | refresh() 階段載入 |
| 單例預實例化 | 否(getBean 時創建) | 是(finishBeanFactoryInitialization) |
| 國際化 | 不支持 | MessageSource |
| 資源加載 | 僅構造時指定的 Resource | ResourceLoader 接口,支援多路徑、通配符 |
| 事件發布 | 不支持 | ApplicationEventPublisher |
| 生命週期回調 | 不支持 | 支援 @PostConstruct、@PreDestroy、InitializingBean、DisposableBean |
| Web 整合 | 不支持 | WebApplicationContext、ServletContext 感知 |
| 父子上下文 | 僅構造函數傳入 parentBeanFactory | 標準化父子上下文體系、遞歸查找 |
現代替代方案:GenericApplicationContext + XmlBeanDefinitionReader
GenericApplicationContext context = new GenericApplicationContext();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
reader.loadBeanDefinitions("classpath:beans.xml");
context.refresh(); // 觸發完整初始化
// 使用 context.getBean(...)
這提供了 XmlBeanFactory 的簡潔性,同時擁有 ApplicationContext 的完整企業級功能。
總結
XmlBeanFactory 雖輕量,但完整展示了 Spring 容器啟動的 三大核心階段:
- 資源定位:
Resource 抽象統一訪問類路徑、文件系統、網絡等配置源。
- 元數據解析:
XmlBeanDefinitionReader → DocumentLoader → BeanDefinitionDocumentReader → BeanDefinitionParserDelegate,將 XML 轉為結構化 BeanDefinition。
- 註冊表構建:
BeanDefinitionReaderUtils → DefaultListableBeanFactory.beanDefinitionMap,完成 Bean 定義的集中管理。
理解這條鏈路,配合 BeanDefinition、BeanDefinitionRegistry、ResourceLoader 等核心接口,你就掌握了 Spring IOC 容器「從配置到元數據」的轉化本質——這正是所有高級特性(AOP、事務、MVC、Batch 等)得以建立的基石。
- 上一篇文章: Spring 聲明式事務管理源碼深度解讀(一):事務開始與屬性解析全流程分析
- 下一篇文章: 利用 Stripes、Apache Derby 與 Eclipse 實現零配置 J2EE 開發(二):註解、單元測試與實戰應用
Copyright ©
程式碼之家 All Rights Reserved