【SSH进阶之路】一步步重构容器实现Spring框架——彻底封装,实现简单灵活的Spring框架(十一)

目录
     【SSH进阶之路】一步步重构容器实现Spring框架——从一个简单的容器开始(八)
     【SSH进阶之路】一步步重构容器实现Spring框架——解决容器对组件的“侵入式”管理的两种方案--主动查找和控制反转(九)
     【SSH进阶之路】一步步重构容器实现Spring框架——配置文件+反射实现IoC容器(十)
     【SSH进阶之路】一步步重构容器实现Spring框架——彻底封装,实现简单灵活的Spring框架(十一)

 

      博文【SSH进阶之路】一步步重构容器实现Spring框架——从一个简单的容器开始(八),我们为了去掉接口对具体实现的依赖关系,封装了一个特别简陋的容器。
      博文【SSH进阶之路】一步步重构容器实现Spring框架——解决容器对组件的“侵入式”管理的两种方案--主动查找和控制反转(九),我们利用控制反转,去掉了组件对容器的依赖。

      博文【SSH进阶之路】一步步重构容器实现Spring框架——配置文件+反射实现IoC容器(十),我们实现了读取配置文件,以及容器创建对象的灵活,简单的IoC。

  

      这篇博文的目标是不仅形似spring,而且要神似Spring,进一步封装对象的依赖关系。

      我们知道Spring框架,不仅可以根据配置创建对象,而且可以根据配置创建对象之间的依赖关系。对象之间的依

赖关系怎么配置呢,那我们先看一下配置文件。

 

[html] view plain copy
 
 print?
  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.     <property name="dao" ref="dao"></property>  
  8.   </bean>  
  9.       
  10. </beans>  

 

      我们发现配置文件中多了两个属性:property和ref,表达了Service需要依赖Dao的关系,所以我们需要将dao注入

给Service,怎么做呢?我们只需要像存储bean一样建立一个JavaBean即可:

 

 

[java] view plain copy
 
 print?
  1. public class PropertyDefinition {  
  2.   
  3.     private String name;  
  4.     private String ref;  
  5.   
  6.     public PropertyDefinition(String name, String ref) {  
  7.         this.name = name;  
  8.         this.ref = ref;  
  9.     }  
  10.       
  11.     public String getName() {  
  12.         return name;  
  13.     }  
  14.     public void setName(String name) {  
  15.         this.name = name;  
  16.     }  
  17.     public String getRef() {  
  18.         return ref;  
  19.     }  
  20.     public void setRef(String ref) {  
  21.         this.ref = ref;  
  22.     }  
  23.       
  24. }  


      有了javabean,我们就只需要专注于怎么为bean对象的属性注入值。我们可以利用内省来操作Bean类属性、事

 

件。一般的做法是通过类Introspector来获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器

(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反

射机制来调用这些方法,最后将引用对象注入到属性中。

 

 

[java] view plain copy
 
 print?
  1. import java.beans.Introspector;  
  2. import java.beans.PropertyDescriptor;  
  3. import java.lang.reflect.Method;  
  4. import java.util.ArrayList;  
  5. import java.util.HashMap;  
  6. import java.util.List;  
  7. import java.util.Map;  
  8.   
  9. import org.jdom.Document;  
  10. import org.jdom.Element;  
  11. import org.jdom.input.SAXBuilder;  
  12. import org.jdom.xpath.XPath;  
  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.      * 为bean对象的属性注入值 
  38.      */  
  39.     private void injectObject() {  
  40.         for (BeanDefinition beanDefinition :beanDefines) {  
  41.             Object bean = sigletons.get(beanDefinition.getId());  
  42.             if(bean != null){  
  43.                 try {  
  44.                     // 通过Introspector取得bean的定义信息,之后再取得属性的描述信息,返回一个数组  
  45.                     PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();  
  46.                       
  47.                     for(PropertyDefinition propertyDefinition:beanDefinition.getPropertys()){  
  48.                         for(PropertyDescriptor properdesc: ps){  
  49.                             if(propertyDefinition.getName().equals(properdesc.getName())){  
  50.                                 // 获取属性的setter方法,private  
  51.                                 Method setter = properdesc.getWriteMethod();   
  52.                                 if(setter != null){  
  53.                                     Object value = sigletons.get(propertyDefinition.getRef());  
  54.                                     // 允许访问私有方法  
  55.                                     setter.setAccessible(true);   
  56.                                     // 把引用对象注入到属性  
  57.                                     setter.invoke(bean, value);   
  58.                                 }  
  59.                                 break;  
  60.                             }  
  61.                         }  
  62.                     }  
  63.                 } catch (Exception e) {  
  64.                     e.printStackTrace();  
  65.                 }  
  66.             }  
  67.         }  
  68.     }  
  69.   
  70.     /** 
  71.      * 完成bean的实例化 
  72.      */  
  73.     private void instanceBeans() {  
  74.         for(BeanDefinition beanDefinition : beanDefines){  
  75.             try {  
  76.                 if(beanDefinition.getClassName() != null && !"".equals(beanDefinition.getClassName().trim())){  
  77.                     sigletons.put(beanDefinition.getId(),Class.forName(beanDefinition.getClassName()).newInstance() );  
  78.                 }  
  79.             } catch (Exception e) {  
  80.                 e.printStackTrace();  
  81.             }  
  82.         }  
  83.     }  
  84.   
  85.     /** 
  86.      * 读取xml配置文件 
  87.      */  
  88.     private void readXML(String fileName) {  
  89.         // 创建SAXBuilder对象  
  90.         SAXBuilder saxBuilder = new SAXBuilder();  
  91.   
  92.         try {  
  93.             // 读取资源,获得document对象  
  94.             Document doc = saxBuilder.build(this.getClass().getClassLoader()  
  95.                     .getResourceAsStream(fileName));  
  96.             // 获取根元素  
  97.             Element rootEle = doc.getRootElement();  
  98.             // 从根元素获得所有的子元素,建立元素集合  
  99.             List listBean = XPath.selectNodes(rootEle, "/beans/bean");  
  100.   
  101.             // 遍历根元素的子元素集合,扫描配置文件中的bean  
  102.             for (int i = 0; i < listBean.size(); i++) {  
  103.                  // 将根元素beans下的bean子元素作为一个新的子根元素  
  104.                 Element elementBean = (Element) listBean.get(i);  
  105.                 //获取id属性值  
  106.                 String id = elementBean.getAttributeValue("id");  
  107.                 //获取class属性值  
  108.                 String clazz = elementBean.getAttributeValue("class");  
  109.                   
  110.                 BeanDefinition beanDefine = new BeanDefinition(id,clazz);  
  111.                 // 获取子根元素bean下的所有property子元素  
  112.                 List listProperty = elementBean.getChildren("property");  
  113.                 // 遍历子根元素的子元素集合(即遍历property元素)  
  114.                 for (int j = 0; j < listProperty.size(); j++) {  
  115.                     // 获取property元素  
  116.                     Element elmentProperty = (Element)listProperty.get(j);  
  117.                     // 获取name属性值  
  118.                     String propertyName = elmentProperty.getAttributeValue("name");  
  119.                     // 获取ref属性值  
  120.                     String propertyref = elmentProperty.getAttributeValue("ref");  
  121.                       
  122.                     PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName,propertyref);  
  123.                       
  124.                     beanDefine.getPropertys().add(propertyDefinition);  
  125.                 }  
  126.                   
  127.                 // 将javabean添加到集合中  
  128.                 beanDefines.add(beanDefine);  
  129.             }  
  130.         } catch (Exception e) {  
  131.             e.printStackTrace();  
  132.         }  
  133.     }  
  134.   
  135.   
  136.     /** 
  137.      * 获取bean实例 
  138.      */  
  139.     @Override  
  140.     public Object getBean(String beanName) {  
  141.         return this.sigletons.get(beanName);  
  142.     }  
  143. }  

 

 

此时我们就可以把Service接口的set方法去掉了。

[java] view plain copy
 
 print?
  1. public interface Service {  
  2.     public void serviceMethod();  
  3. }  

 

这里仅有部分代码,大家可以在下面链接中下载。

 

总结

 

        经过四篇博文的重构,我们实现了一个Spring的雏形,它可以让我们更加深刻的认识Spring的原理,对我们更加 

深入的学习Spring埋下了伏笔。

posted on 2017-07-17 17:06  alex5211314  阅读(167)  评论(0编辑  收藏  举报

导航