前面介紹了Spring 框架簡介。今天我們來實(shí)現(xiàn)一個(gè)簡單的Spring IOC容器。
根據(jù)對Spring IOC框架的了解,我們可以將IOC容器簡單抽象為如下四個(gè)步驟:
(1)加載 xml 配置文件,遍歷其中的 <bean> 標(biāo)簽
(2)獲取<bean>標(biāo)簽中的 id 和 class 屬性,加載 class 屬性對應(yīng)的類,并創(chuàng)建 bean
(3)遍歷 <bean> 標(biāo)簽中的 <property> 標(biāo)簽,獲取屬性值,并將屬性值填充到 bean 中
(4)將 bean 注冊到 bean 容器中
只需要如下的幾個(gè)類即可:
- SimpleIOC :IOC 的實(shí)現(xiàn)類,作用為加載XML文件注冊到容器之中
- SimpleIOCTest : 測試類
- Car :bena 類
- Wheel : bean 類
- ioc.xml : XML配置文件
項(xiàng)目代碼
- SimpleIOC.java
public class SimpleIOC {
private Map<String, Object> beanMap = new HashMap<>();
public SimpleIOC(String location) throws Exception {
loadBeans(location);
}
public Object getBean(String name) {
Object bean = beanMap.get(name);
if (bean == null) {
throw new IllegalArgumentException("there is no bean with name " + name);
}
return bean;
}
private void loadBeans(String location) throws Exception {
// 加載 xml 配置文件
InputStream inputStream = new FileInputStream(location);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(inputStream);
Element root = doc.getDocumentElement();
NodeList nodes = root.getChildNodes();
// 遍歷 <bean></bean> 標(biāo)簽
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
String id = ele.getAttribute("id");
String className = ele.getAttribute("class");
Class beanClass = null;
try {
beanClass = Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
return;
}
Object bean = beanClass.newInstance();
// 處理 bean property 屬性
NodeList propertyNodes = ele.getElementsByTagName("property");
for (int j = 0; j < propertyNodes.getLength(); j++) {
Node propertyNode = propertyNodes.item(j);
if (propertyNode instanceof Element) {
Element propertyElement = (Element) propertyNode;
String name = propertyElement.getAttribute("name");
String value = propertyElement.getAttribute("value");
Field declaredField = bean.getClass().getDeclaredField(name);
declaredField.setAccessible(true);
if (value != null && value.length() > 0) {
declaredField.set(bean, value);
} else {
String ref = propertyElement.getAttribute("ref");
if (ref == null || ref.length() == 0) {
throw new IllegalArgumentException("ref config error");
}
declaredField.set(bean, getBean(ref));
}
// 將 bean 注冊到 bean 容器中
registerBean(id, bean);
}
}
}
}
}
private void registerBean(String id, Object bean) {
beanMap.put(id, bean);
}
}
- SimpleIOCTest.java
public class SimpleIOCTest {
@Test
public void getBean() throws Exception {
String location = SimpleIOC.class.getClassLoader().getResource("toy-spring-ioc.xml").getFile();
SimpleIOC bf = new SimpleIOC(location);
Wheel wheel = (Wheel) bf.getBean("wheel");
System.out.println(wheel);
Car car = (Car) bf.getBean("car");
System.out.println(car);
}
}
- Car.java
public class Car {
private String name;
private String length;
private String width;
private String height;
private Wheel wheel;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLength() {
return length;
}
public void setLength(String length) {
this.length = length;
}
public String getWidth() {
return width;
}
public void setWidth(String width) {
this.width = width;
}
public String getHeight() {
return height;
}
public void setHeight(String height) {
this.height = height;
}
public Wheel getWheel() {
return wheel;
}
public void setWheel(Wheel wheel) {
this.wheel = wheel;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", length='" + length + '\'' +
", width='" + width + '\'' +
", height='" + height + '\'' +
", \nwheel=" + wheel +
'}';
}
}
- Wheel.java
public class Wheel {
private String brand;
private String specification ;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getSpecification() {
return specification;
}
public void setSpecification(String specification) {
this.specification = specification;
}
@Override
public String toString() {
return "Wheel{" +
"brand='" + brand + '\'' +
", specification='" + specification + '\'' +
'}';
}
}