作为spring框架中的重要思想,ioc(控制反转)是面试中的常客。关于如何理解ioc容器,可以通过自己实现一个简单的ioc容器来领会
步骤分析
简单来说,ioc就是实现了通过配置文件创建对象功能,核心部分就是依赖注入,实现步骤如下:
- 加载配置文件
- 遍历bean标签,获取id和class值
- 加载class类并创建bean
- 遍历 < property > 标签,把属性值填充到相关字段
- 把bean注册到容器当中
IOC容器实现类
直接看代码和注释:
private Map<String, Object> beanmap = new HashMap<String, Object>();
public IOCDemo(String location) throws Exception {
loadBeans(location);
}
private void loadBeans(String location) throws Exception {
// 读取配置文件
InputStream is = new FileInputStream(location);
// 读入.xml文档需要一个DocumentBuilder对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
// 通过java IO 流的读取文件
Document document = docBuilder.parse(is);
Element root = document.getDocumentElement();
NodeList nodes = root.getChildNodes();
// 遍历bean标签
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if (node instanceof Element) {
Element e = (Element) node;
String id = e.getAttribute("id");
String classname = e.getAttribute("class");
// 加载beanClass
Class beanClass = null;
beanClass = Class.forName(classname);
// 创建bean
Object bean = beanClass.newInstance();
// 遍历 <property> 标签
NodeList propertiesList = e.getElementsByTagName("property");
for (int j = 0; j < propertiesList.getLength(); j++) {
Node propertyNode = propertiesList.item(j);
if (propertyNode instanceof Element) {
Element proElement = (Element) propertyNode;
String name = proElement.getAttribute("name");
String value = proElement.getAttribute("value");
// 利用反射将bean相关字段f访问权限设为可访问
Field declaredField = bean.getClass().getDeclaredField(name);
declaredField.setAccessible(true);
if (value != null && value.length() > 0) {
// 把属性值填充到相关字段
declaredField.set(bean, value);
} else {
String ref = proElement.getAttribute("ref");
if (ref == null || ref.length() == 0) {
throw new IllegalArgumentException("ref config error");
}
declaredField.set(bean, getBean(ref));
}
// 把bean注册到容器当中
beanmap.put(id, bean);
}
}
}
}
}
获取bean的方法:
public Object getBean(String name) {
// TODO Auto-generated method stub
Object bean = beanmap.get(name);
if (bean == null) {
throw new IllegalArgumentException("there is no bean with name " + name);
}
return bean;
}
测试
接下来测试一下好不好使:
- 配置文件:
<bean id="computer" class="com.ioc.entry.Computer">
<property name="name" value="拯救者 Y7000"/>
<property name="weight" value="2.3kg"/>
<property name="size" value="15.6英寸"/>
</bean>
- 实体类
public class Computer {
private String name;
private String weight;
private String size;
//...省略get/set方法
}
- 测试类
String location = IOCDemo.class.getClassLoader().getResource("resource/test.xml").getFile();
IOCDemo demo = new IOCDemo(location);
Computer computer = (Computer) demo.getBean("computer");
System.out.println(computer);
- 结果
Computer [name=拯救者 Y7000, weight=2.3kg, size=15.6英寸]