简易spring的IOC实现
首先需要理解一下什么叫做ioc(inversion of Controller),简单来说就是控制反转。它不是一门像js这样的技术,我们可以把它看做一种设计模式。为什么会出现IOC呢?
传统的程序会导致类与类之间高耦合,难以测试,于是就把创建和查找依赖对象的控制权都交给一个容器,由容器来进行注入组合对象。这里可以把容器比作一个菜篮,以前没有菜篮的时候去买白菜的时候就特别不方便,后来有了篮子,不仅装东西方便,而且还送货上门,你只需要说一声,我需要白菜,直接送到家门口。spring就相当于这个篮子。它体现了一个法则:“不管怎样都不要来找我们,我们有需要的时候回来找你的”。接下来我就把一个简易的spring的IOC展示出来。
主要步骤
- 写一个IOC的类,用来解析配置文件,当然配置文件有很多种,但是这里我就用了一个xml的配置文件。这里面要用到反射的知识。
- 遍历xml文件中的所有的bean标签
- 获取bean标签里面的id和class属性,加载class对应的类,并创建bean
- 获取property标签的属性值,并填充到bean中
- 将bean注册到bean容器中
主要文件
- 首先有一个xml文件,我给它取名为springIoc
- 然后是读取xml文件的
MySimpleIOC文件 - 然后有实体类,也就是model,我这里用了Student和studentClass
- 最后就是一个测试类(我用的是junit进行的测试)
关键代码展示[^code]
这里主要是读取xml文件的整个过程,也是整个实现IOC的关键,至于其他的就不做过多的阐述 |
public MySimpleIOC(String location) throws Exception{
loadBeans(location);
}
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 = ((Node) root).getChildNodes();
for(int i = 0;i < nodes.getLength();i++){
Node node = (Node) nodes.item(i);
if(node instanceof Element){
Element element = (Element) node;
String id = element.getAttribute("id");
String className = element.getAttribute("class");
//加载beanClass
Class beanClass = null;
try{
beanClass = Class.forName(className);
}catch(ClassNotFoundException e){
e.printStackTrace();
return;
}
//创建bean
Object bean = beanClass.newInstance();
//遍历<property>标签
NodeList propertyNodes = element.getElementsByTagName("property");
for(int j = 0;j < propertyNodes.getLength();j++){
Node properNode = (Node) propertyNodes.item(j);
if(properNode instanceof Element){
Element propertyElement = (Element) properNode;
String name = propertyElement.getAttribute("name");
String value = propertyElement.getAttribute("value");
//利用反射将bean相关字段访问权限设为可访问
Field declaredField = bean.getClass().getDeclaredField(name);
String tString = declaredField.getType().getName();
declaredField.setAccessible(true);
if(value != null && value.length() > 0){
if(tString.equals("java.lang.Integer")){
Integer temp = Integer.parseInt(value);
declaredField.set(bean, temp);
}else{
//将属性填充到相关字段中
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);
}
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;
}
刚刚说了关键就是上面那个步骤,下面我将测试类代码也展示一下。
@Test
public void getBean() throws Exception{
String location = MySimpleIOC.class.getClassLoader().getResource("springIoc.xml").getFile();
String temp = location.substring(1, location.length());
MySimpleIOC ioc = new MySimpleIOC(temp);
StudentClass studentClass = (StudentClass) ioc.getBean("studentClass");
System.out.println(studentClass + "," +studentClass.getCode() +","+ studentClass.getMark());
Student student = (Student) ioc.getBean("student");
System.out.println(student+"," +student.getName()+","+student.getStudentClass().getCode());
}