org.jdom:jdom2:2.0.6模擬 Spring 核心機制:解析 XML → 反射創建 Bean → 註冊容器 → 獲取使用
// 統一行為介面
public interface Moveable {
void run();
}
// 實現類
public class Plane implements Moveable {
@Override public void run() { System.out.println("飛機在翱翔....."); }
}
public class Train implements Moveable {
@Override public void run() { System.out.println("火車在飛奔...."); }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="train" class="com.example.xml.Train"/>
<bean id="plane" class="com.example.xml.Plane"/>
</beans>
public interface BeanFactory {
Object getBean(String id);
}
public class ClassPathXmlApplicationContext implements BeanFactory {
private final Map beanContainer = new HashMap<>();
public ClassPathXmlApplicationContext(String xmlPath) throws Exception {
// 1. 創建 SAXBuilder(JDOM 解析器)
SAXBuilder builder = new SAXBuilder();
// 2. 從 classpath 讀取輸入流
InputStream is = getClass().getClassLoader().getResourceAsStream(xmlPath);
if (is == null) throw new IllegalArgumentException("XML not found: " + xmlPath);
// 3. 構建 Document 物件樹
Document document = builder.build(is);
// 4. 獲取根元素
Element root = document.getRootElement(); //
// 5. XPath 選擇所有 bean 元素
List beanElements = XPathFactory.instance()
.compile("/beans/bean", Filters.element())
.evaluate(root);
// 6. 遍歷解析並實例化
for (Element beanElem : beanElements) {
String id = beanElem.getAttributeValue("id");
String className = beanElem.getAttributeValue("class");
if (id == null || className == null) {
throw new IllegalArgumentException("bean 缺少 id 或 class: " + beanElem);
}
// 反射創建實例
Class> clazz = Class.forName(className);
Object bean = clazz.getDeclaredConstructor().newInstance();
// 註冊到容器
beanContainer.put(id, bean);
System.out.println("註冊 Bean: " + id + " -> " + className);
}
}
@Override
public Object getBean(String id) {
return beanContainer.get(id);
}
}
public class Main {
public static void main(String[] args) throws Exception {
// 初始化容器(解析 XML、創建 Bean)
BeanFactory factory = new ClassPathXmlApplicationContext("beans.xml");
// 獲取 Bean 並使用
Moveable train = (Moveable) factory.getBean("train");
train.run(); // 輸出: 火車在飛奔....
Moveable plane = (Moveable) factory.getBean("plane");
plane.run(); // 輸出: 飛機在翱翔.....
}
}
<bean id="car" class="com.example.Car">
<property name="brand" value="Toyota"/>
<property name="engine" ref="engine"/>
</bean>
<bean id="engine" class="com.example.Engine"/>
// 解析邏輯擴展
Element beanElem = ...;
Object bean = clazz.getDeclaredConstructor().newInstance();
// 處理
List props = beanElem.getChildren("property");
for (Element prop : props) {
String name = prop.getAttributeValue("name");
String value = prop.getAttributeValue("value");
String ref = prop.getAttributeValue("ref");
Object propValue = (ref != null) ? beanContainer.get(ref) : convertValue(value, targetType);
// 反射調用 setter
String setter = "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
clazz.getMethod(setter, propValue.getClass()).invoke(bean, propValue);
}
<bean id="singletonBean" class="..." scope="singleton"/>
<bean id="prototypeBean" class="..." scope="prototype"/>
// 容器邏輯
String scope = beanElem.getAttributeValue("scope", "singleton");
if ("prototype".equals(scope)) {
// 每次 getBean 重新創建
return clazz.getDeclaredConstructor().newInstance();
} else {
// 單例:容器持有
return beanContainer.computeIfAbsent(id, k -> createBean(beanElem));
}
<bean id="service" class="..." init-method="init" destroy-method="close"/>
// 初始化
if (initMethod != null) clazz.getMethod(initMethod).invoke(bean);
// 銷毀(容器關閉時)
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
beanContainer.values().forEach(b -> {
try { destroyMethod.invoke(b); } catch (Exception ignored) {}
});
}));
| 解析器 | 模型 | 適用場景 | 記憶體 |
|---|---|---|---|
| DOM / JDOM | 樹 | 中小文檔、需隨機存取、修改寫回 | 整個文檔載入記憶體 |
| SAX | 事件流 | 大文檔、單次順序讀取、低記憶體 | 極低 |
| StAX | 拉取流 | 大文檔、需控制解析流程 | 低 |
| JAXB | 綁定 | XML⇄物件映射、Schema 驅動 | 中等 |
| dom4j | 樹 | 類 JDOM、XPath 支援更強、Hibernate 早期使用 | 整個文檔 |