自己寫一個簡單的Spring IOC容器
阿新 • • 發佈:2019-01-02
為了能更好的理解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方法:
BImpl程式碼,通過介面呼叫a的print方法,必須有setter方法,因為在IOC容器中會利用反射機制呼叫該方法:package demo.myspring.impl; import demo.myspring.A; public class AImpl implements A { @Override public void print() { System.out.println("AImpl invoked!"); } }
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
bean.xml檔案: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); } }
<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!