一、IOC實現
1.實現步驟
最簡單的 IOC 容器只需 4 步即可實現,如下:
- 加載 xml 配置文件,遍歷其中的 <bean> 標籤
- 獲取 <bean> 標籤中的 id 和 class 屬性,加載 class 屬性對應的類,並創建 bean
- 遍歷 <bean> 標籤中的 <property> 標籤,獲取屬性值,並將屬性值填充到 bean 中
- 將 bean 註冊到 bean 容器中
2.實現代碼
【代碼結構】
SimpleIOC // IOC 的實現類,實現了上面所說的4個步驟
SimpleIOCTest // IOC 的測試類
Car // IOC 測試使用的 bean
Wheel // 同上
ioc.xml // bean 配置文件
【容器實現類 SimpleIOC 的代碼】
package learn.spring.ioc;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class SimpleIOC {
// bean 容器
private Map<String,Object> container = new HashMap<>();
/**
* 構造器
* @param name 初始化的xml文件名
* */
public SimpleIOC(String name) throws Exception {
loadBean(name);
}
/**
* 從容器中獲取bean
* @param name 要獲取的bean name
* */
public Object getBean(String name) {
Object bean = container.get(name);
if (bean == null) {
throw new IllegalArgumentException("there is no the bean of " + name);
}
return bean;
}
/**
* 把xml文件中的bean實例化並存放到容器中
* @param name 初始化的xml文件名
* */
private void loadBean(String name) throws Exception {
/*加載xml文件*/
// 創建文件輸入流
File file = new File(name);
// 創建xml解析器
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder document = factory.newDocumentBuilder();
// 解析文件輸入流,獲得文檔對象
Document xml = document.parse(file);
Element element = xml.getDocumentElement();
// 獲取所有子節點集合,即獲得bean節點,這裏根據xml文件來獲得
NodeList nodes = element.getChildNodes();
// NodeList list = element.getElementsByTagName("bean"); //獲取指定節點集合
// 遍歷bean節點
for (int i = 0; i<nodes.getLength(); i++) {
// 獲得單個bean
Node node = nodes.item(i);
// 保證bean內部存在元素
if (node instanceof Element) {
Element ele = (Element)node;
String id = ele.getAttribute("id");
String className = ele.getAttribute("class");
// 加載beanClass
Class beanClass = null;
try {
beanClass = Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
return ;
}
// 創建bean對象
Object bean = beanClass.newInstance();
// 遍歷property標籤,跟遍歷bean相同
NodeList propertyList = ele.getElementsByTagName("property");
for (int j = 0; j < propertyList.getLength(); j ++) {
Node propertyNode = propertyList.item(j);
if (propertyNode instanceof Element) {
Element eleProperty = (Element) propertyNode;
// 獲得屬性
String propertyName = eleProperty.getAttribute("name");
String propertyValue = eleProperty.getAttribute("value");
// 利用反射將bean相關字段設置爲可訪問,原權限是private
Field field = bean.getClass().getDeclaredField(propertyName);
field.setAccessible(true);
// 存在value屬性
if (propertyValue != null && propertyValue.length()>0) {
field.set(bean,propertyValue);
} else {// 屬性不是基本類,而是其他類
String ref = eleProperty.getAttribute("ref");
if (ref == null || ref.length()==0) {
throw new IllegalArgumentException("ref property error");
}
// 獲取bean,並填充到相關字段
field.set(bean,getBean(ref));
}
}
}
registerBean(id,bean);
}
}
}
private void registerBean(String id, Object bean) {
container.put(id,bean);
}
}
【配置文件代碼】
<beans>
<bean id="wheel" class="learn.spring.ioc.Wheel">
<property name="brand" value="Michelin" />
<property name="specification" value="265/60 R18" />
</bean>
<bean id="car" class="learn.spring.ioc.Car">
<property name="name" value="Mercedes Benz G 500"/>
<property name="length" value="4717mm"/>
<property name="width" value="1855mm"/>
<property name="height" value="1949mm"/>
<property name="wheel" ref="wheel"/>
</bean>
</beans>
【容器測試使用的 bean 代碼】
package learn.spring.ioc;
public class Wheel {
private String brand;
private String specification ;
public String getBrand() {
return brand;
}
public String getSpecification() {
return specification;
}
public void setBrand(String brand) {
this.brand = brand;
}
public void setSpecification(String specification) {
this.specification = specification;
}
@Override
public String toString() {
return this.getBrand()+":"+this.getSpecification();
}
}
package learn.spring.ioc;
public class Car {
private String name;
private String length;
private String width;
private String height;
private Wheel wheel;
public void setName(String name) {
this.name = name;
}
public void setLength(String length) {
this.length = length;
}
public void setWidth(String width) {
this.width = width;
}
public void setHeight(String height) {
this.height = height;
}
public void setWheel(Wheel wheel) {
this.wheel = wheel;
}
public String getName() {
return name;
}
public String getLength() {
return length;
}
public String getWidth() {
return width;
}
public String getHeight() {
return height;
}
public Wheel getWheel() {
return wheel;
}
@Override
public String toString() {
return this.getName()+"+"+this.getHeight()
+"+"+this.getLength()+"+"+this.getWidth()+"+"+this.getWheel().toString();
}
}
【測試類】
package learn.spring.ioc;
public class Main {
public static void main(String[] args) throws Exception {
// 指定配置文件的路徑
String location = "src/learn/spring/ioc/configuration";
SimpleIOC simpleIOC = new SimpleIOC(location);
Wheel wheel = (Wheel) simpleIOC.getBean("wheel");
System.out.println(wheel);
Car car = (Car) simpleIOC.getBean("car");
System.out.println(car);
}
}
【運行結果】
Michelin:265/60 R18
Mercedes Benz G 500+1949mm+4717mm+1855mm+Michelin:265/60 R18