一、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