1. 程式人生 > >自己寫一個簡單的Spring IOC容器

自己寫一個簡單的Spring IOC容器

為了能更好的理解SpirngIOC是如何工作的,在查閱網上的資料後,自己寫了一個非常簡單的SpringIOC容器,使用setter方法將值注入。

本例子需要用到jdom的包:http://pan.baidu.com/s/1hsmgsfi

以下是包結構


A和B介面的定義就不不寫類,很簡單。

BeanFactory介面只有一個方法,根據id返回對應的bean:

package demo.myspring;

public interface BeanFactory {
	public Object getBean(String id);
}

AImpl程式碼,只有一個print方法:

package demo.myspring.impl;

import demo.myspring.A;

public class AImpl implements A {

	@Override
	public void print() {
		System.out.println("AImpl invoked!");
	}

}
BImpl程式碼,通過介面呼叫a的print方法,必須有setter方法,因為在IOC容器中會利用反射機制呼叫該方法:
package demo.myspring.impl;

import demo.myspring.A;

public class BImpl implements demo.myspring.B {
	A a;

	public void setA(A a) {
		this.a = a;
	}
	
	public void print(){
		System.out.println("BImpl invoked!");
		a.print();
	}
}

ClassPathXmlApplicationContext程式碼,主要是利用SAXBulider解析Bean.xml檔案,在利用反射機制載入bean
package demo.myspring.core;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

import demo.myspring.BeanFactory;

public class ClassPathXmlApplicationContext implements BeanFactory {

	private Map<String, Object> beans = new HashMap<String,Object>();
	
	public ClassPathXmlApplicationContext() throws Exception{
		
		SAXBuilder sb = new SAXBuilder();//新建xml解析器
		
		Document xmlDoc = sb.build(this.getClass().getClassLoader().
					      getResourceAsStream("demo/myspring/conf/beans.xml"));//構造文件物件
		Element root = xmlDoc.getRootElement();//獲取根元素
		List<Element> list = root.getChildren("bean");//獲取根元素下所有名字為bean的元素
		
		//遍歷所有的bean元素,並將其放入beans中
		for(int i = 0;i<list.size();i++){
			Element e = (Element)list.get(i);//獲取Element元素
			String id = e.getAttributeValue("id");//獲取property的id屬性的值
			String clazz = e.getAttributeValue("class");//獲取property的class屬性的值
			Object o = Class.forName(clazz).newInstance();//利用反射生成一個具體的例項
			System.out.println(" id: "+id+" class: "+clazz);
			beans.put(id, o);//將bean放入一個HashMap
			//遍歷bean下的所有properyt屬性,並呼叫setter方法,將值注入給對應的屬性
			if(e.getChild("property")!=null){
				for(Element p : (List<Element>)e.getChildren("property")){
					String name = p.getAttributeValue("name");
					String bean = p.getAttributeValue("bean");
					Object beanObject = beans.get(bean);
					String methodName = "set" + name.substring(0,1).toUpperCase()+ name.substring(1);
					System.out.println("setter method name = " +methodName);
					Method m = o.getClass().getMethod(methodName,beanObject.getClass().getInterfaces()[0]);
					m.invoke(o,beanObject);//呼叫setter方法
				}
			}	
		}		
	}
	
	public Object getBean(String id) {
		return beans.get(id);
	}

}
bean.xml檔案:
<beans>
	<bean id="a" class="demo.myspring.impl.AImpl"/>
	<bean id="b" class="demo.myspring.impl.BImpl">
		<property name="a" bean = "a" />
	</bean>
</beans>
測試類:
package demo.myspring.test;

import demo.myspring.B;
import demo.myspring.core.ClassPathXmlApplicationContext;

public class Test {
	public static void main(String[] args) throws Exception{
		ClassPathXmlApplicationContext cpxa = new ClassPathXmlApplicationContext();
		B b = (B) cpxa.getBean("b");
		b.print();
	}
}
測試類執行後,控制檯輸出如下資訊

 id: a class: demo.myspring.impl.AImpl
 id: b class: demo.myspring.impl.BImpl
setter method name = setA
BImpl invoked!
AImpl invoked!