一步步重構容器實現Spring框架——配置文件+反射實現IoC容器(十)

上篇博文容器初始化時,使用new的方式來實力化對象,這篇博文咱們利用配置文件+反射實力化對象,進一步封html

裝下降容器和組件的耦合度。下面咱們先看一下配置文件。java

 

[html] view plain copydom

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans>  
  3.   
  4.   <bean id="dao" class="com.tgb.container.dao.impl.Dao4MySqlImpl" />  
  5.     
  6.   <bean id="service" class="com.tgb.container.service.impl.ServiceImpl" />  
  7.       
  8. </beans>  

      看到上面的配置文件,除了命名空間沒有,和Spring的配置文件已經很像了,下面咱們就使用dom4j或jdom來讀取ide

配置文件,並將配置文件中配置類利用反射實例化。本實例咱們使用的jdom,你們也可使用dom4j試一下。下面我ui

們看一下讀取配置文件的代碼:this

 

[java] view plain copyspa

  1. public interface BeanFactory {  
  2.   
  3.     Object getBean(String id);  
  4. }  

[java] view plain copy.net

  1. import java.util.HashMap;  
  2. import java.util.List;  
  3. import java.util.Map;  
  4.   
  5. import org.jdom.Document;  
  6. import org.jdom.Element;  
  7. import org.jdom.input.SAXBuilder;  
  8. import org.jdom.xpath.XPath;  
  9.   
  10. import com.tgb.container.dao.Dao;  
  11. import com.tgb.container.service.Service;  
  12.   
  13. /** 
  14.  * 從類路徑加載配置文件 
  15.  *  
  16.  * @author liang 
  17.  *  
  18.  */  
  19. public class ClassPathXmlApplicationContext implements BeanFactory {  
  20.   
  21.     // 用於存放Bean  
  22.     private Map<String, Object> beans = new HashMap<String, Object>();  
  23.   
  24.     public ClassPathXmlApplicationContext(String fileName) {  
  25.   
  26.         this.readXML(fileName);  
  27.   
  28.     }  
  29.   
  30.     // 解析xml文件,經過反射將配置的beasn放到container中,並實現依賴注入  
  31.     private void readXML(String fileName) {  
  32.         // 建立SAXBuilder對象  
  33.         SAXBuilder saxBuilder = new SAXBuilder();  
  34.         // 讀取資源,得到document對象  
  35.         Document doc;  
  36.         try {  
  37.             doc = saxBuilder.build(this.getClass().getClassLoader().getResourceAsStream(fileName));  
  38.   
  39.             // 獲取根元素  
  40.             Element rootEle = doc.getRootElement();  
  41.             // 從根元素得到全部的子元素,創建元素集合  
  42.             List listBean = XPath.selectNodes(rootEle, "/beans/bean");  
  43.   
  44.             // 遍歷根元素的子元素集合,掃描配置文件中的bean  
  45.             for (int i = 0; i < listBean.size(); i++) {  
  46.                 Element bean = (Element) listBean.get(i);  
  47.                 // 獲取id屬性值  
  48.                 String id = bean.getAttributeValue("id");  
  49.                 // 獲取class屬性值  
  50.                 String clazz = bean.getAttributeValue("class");  
  51.                 // 反射,實例化  
  52.                 Object o = Class.forName(clazz).newInstance();  
  53.                 beans.put(id, o);  
  54.             }  
  55.   
  56.             // 依賴管理,這裏還不靈活,可是原理是同樣的  
  57.             Service service = (Service) beans.get("service");  
  58.             Dao dao = (Dao) beans.get("dao");  
  59.             // 依賴注入,Service實現依賴dao的實現  
  60.             service.setDao(dao);  
  61.   
  62.         } catch (Exception e) {  
  63.   
  64.             e.printStackTrace();  
  65.         }  
  66.     }  
  67.   
  68.     /** 
  69.      * 查找組件 
  70.      *  
  71.      * @param id 
  72.      * @return 
  73.      */  
  74.     @Override  
  75.     public Object getBean(String id) {  
  76.         return beans.get(id);  
  77.     }  
  78. }  


     看到上面的代碼,咱們發現讀取配置文件的方法中包含了反射,代碼的可讀性太差,而且對面向對象的封裝不夠徹xml

 

底,下面咱們將bean的實例化以及依賴注入進行進一步的封裝。htm

 

 

封裝bean的實例化

 

       爲了作進一步的封裝,咱們將配置文件的屬性封裝成一個javabean,爲了存放咱們的屬性值。以下所示:

 

[java] view plain copy

  1. public class BeanDefinition {  
  2.   
  3.     private String id;  
  4.     private String className;  
  5.   
  6.       
  7.     public BeanDefinition(String id, String className) {  
  8.         this.id = id;  
  9.         this.className = className;  
  10.     }  
  11.   
  12.     public String getId() {  
  13.         return id;  
  14.     }  
  15.   
  16.     public void setId(String id) {  
  17.         this.id = id;  
  18.     }  
  19.   
  20.     public String getClassName() {  
  21.         return className;  
  22.     }  
  23.   
  24.     public void setClassName(String className) {  
  25.         this.className = className;  
  26.     }  
  27.   
  28. }  


     如今咱們就能夠把bean的實例化作進一步的封裝了。

 

 

[java] view plain copy

  1. import java.util.ArrayList;  
  2. import java.util.HashMap;  
  3. import java.util.List;  
  4. import java.util.Map;  
  5.   
  6. import org.jdom.Document;  
  7. import org.jdom.Element;  
  8. import org.jdom.input.SAXBuilder;  
  9. import org.jdom.xpath.XPath;  
  10.   
  11. import com.tgb.container.dao.Dao;  
  12. import com.tgb.container.service.Service;  
  13.   
  14. /** 
  15.  * 容器 
  16.  *  
  17.  * @author liang 
  18.  *  
  19.  */  
  20. public class ClassPathXmlApplicationContext implements BeanFactory {  
  21.   
  22.     // 用於存放Bean  
  23.     private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();  
  24.     // 用於存放Bean的實例  
  25.     private Map<String, Object> sigletons =new HashMap<String, Object>();  
  26.       
  27.       
  28.     public ClassPathXmlApplicationContext(String fileName) {  
  29.   
  30.         this.readXML(fileName);  
  31.           
  32.         this.instanceBeans();  
  33.           
  34.         this.injectObject();  
  35.     }  
  36.   
  37.     /** 
  38.      * 依賴注入,爲bean對象的屬性注入值 
  39.      * 這裏還不靈活,可是原理是同樣的 
  40.      */  
  41.     private void injectObject() {  
  42.         Service service = (Service) this.sigletons.get("service");  
  43.         Dao dao = (Dao) this.sigletons.get("dao");  
  44.         //依賴注入,Service實現依賴dao的實現  
  45.         service.setDao(dao);  
  46.     }  
  47.   
  48.     /** 
  49.      * 完成bean的實例化 
  50.      */  
  51.     private void instanceBeans() {  
  52.         for(BeanDefinition beanDefinition : beanDefines){  
  53.             try {  
  54.                 if(beanDefinition.getClassName() != null && !"".equals(beanDefinition.getClassName().trim())){  
  55.                     sigletons.put(beanDefinition.getId(),Class.forName(beanDefinition.getClassName()).newInstance() );  
  56.                 }  
  57.             } catch (Exception e) {  
  58.                 e.printStackTrace();  
  59.             }  
  60.         }  
  61.     }  
  62.   
  63.     /** 
  64.      * 讀取xml配置文件 
  65.      */  
  66.     private void readXML(String fileName) {  
  67.         // 建立SAXBuilder對象  
  68.         SAXBuilder saxBuilder = new SAXBuilder();  
  69.   
  70.         try {  
  71.             // 讀取資源,得到document對象  
  72.             Document doc = saxBuilder.build(this.getClass().getClassLoader()  
  73.                     .getResourceAsStream(fileName));  
  74.             // 獲取根元素  
  75.             Element rootEle = doc.getRootElement();  
  76.             // 從根元素得到全部的子元素,創建元素集合  
  77.             List listBean = XPath.selectNodes(rootEle, "/beans/bean");  
  78.   
  79.             // 遍歷根元素的子元素集合,掃描配置文件中的bean  
  80.             for (int i = 0; i < listBean.size(); i++) {  
  81.                 Element bean = (Element) listBean.get(i);  
  82.                 // 獲取id屬性值  
  83.                 String id = bean.getAttributeValue("id");  
  84.                 // 獲取class屬性值  
  85.                 String clazz = bean.getAttributeValue("class");  
  86.                   
  87.                 BeanDefinition beanDefine = new BeanDefinition(id,clazz);  
  88.                 // 將javabean添加到集合中  
  89.                 beanDefines.add(beanDefine);  
  90.             }  
  91.         } catch (Exception e) {  
  92.             e.printStackTrace();  
  93.         }  
  94.     }  
  95.   
  96.   
  97.     /** 
  98.      * 獲取bean實例 
  99.      */  
  100.     @Override  
  101.     public Object getBean(String beanName) {  
  102.         return this.sigletons.get(beanName);  
  103.     }  
  104.   
  105. }  

 

      咱們知道容器不只負責建立對象,並且能夠管理對象的依賴關係,管理對象的生命週期等等。咱們僅實現了容器

靈活建立對象的部分,依賴注入部分是由咱們手動注入的。 對象的依賴關係還不靈活,可是咱們已經可以看到IoC的

影子了,只是形似,尚未達到神似的目標。

相關文章
相關標籤/搜索