您的位置:首页 > 编程语言 > Java开发

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

2017-04-20 22:06 627 查看
目录

     【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?





<?xml version="1.0" encoding="UTF-8"?>  

<beans>  

  

  <bean id="dao" class="com.tgb.container.dao.impl.Dao4MySqlImpl" />  

    

  <bean id="service" class="com.tgb.container.service.impl.ServiceImpl">  

    <property name="dao" ref="dao"></property>  

  </bean>  

      

</beans>  

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

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

[java] view
plain copy

 print?





public class PropertyDefinition {  

  

    private String name;  

    private String ref;  

  

    public PropertyDefinition(String name, String ref) {  

        this.name = name;  

        this.ref = ref;  

    }  

      

    public String getName() {  

        return name;  

    }  

    public void setName(String name) {  

        this.name = name;  

    }  

    public String getRef() {  

        return ref;  

    }  

    public void setRef(String ref) {  

        this.ref = ref;  

    }  

      

}  

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

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

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

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

[java] view
plain copy

 print?





import java.beans.Introspector;  

import java.beans.PropertyDescriptor;  

import java.lang.reflect.Method;  

import java.util.ArrayList;  

import java.util.HashMap;  

import java.util.List;  

import java.util.Map;  

  

import org.jdom.Document;  

import org.jdom.Element;  

import org.jdom.input.SAXBuilder;  

import org.jdom.xpath.XPath;  

  

/** 

 * 容器 

 *  

 * @author liang 

 *  

 */  

public class ClassPathXmlApplicationContext implements BeanFactory {  

  

    // 用于存放Bean  

    private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();  

    // 用于存放Bean的实例  

    private Map<String, Object> sigletons =new HashMap<String, Object>();  

      

      

    public ClassPathXmlApplicationContext(String fileName) {  

  

        this.readXML(fileName);  

          

        this.instanceBeans();  

          

        this.injectObject();  

    }  

    /** 

     * 为bean对象的属性注入值 

     */  

    private void injectObject() {  

        for (BeanDefinition beanDefinition :beanDefines) {  

            Object bean = sigletons.get(beanDefinition.getId());  

            if(bean != null){  

                try {  

                    // 通过Introspector取得bean的定义信息,之后再取得属性的描述信息,返回一个数组  

                    PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();  

                      

                    for(PropertyDefinition propertyDefinition:beanDefinition.getPropertys()){  

                        for(PropertyDescriptor properdesc: ps){  

                            if(propertyDefinition.getName().equals(properdesc.getName())){  

                                // 获取属性的setter方法,private  

                                Method setter = properdesc.getWriteMethod();   

                                if(setter != null){  

                                    Object value = sigletons.get(propertyDefinition.getRef());  

                                    // 允许访问私有方法  

                                    setter.setAccessible(true);   

                                    // 把引用对象注入到属性  

                                    setter.invoke(bean, value);   

                                }  

                                break;  

                            }  

                        }  

                    }  

                } catch (Exception e) {  

                    e.printStackTrace();  

                }  

            }  

        }  

    }  

  

    /** 

     * 完成bean的实例化 

     */  

    private void instanceBeans() {  

        for(BeanDefinition beanDefinition : beanDefines){  

            try {  

                if(beanDefinition.getClassName() != null && !"".equals(beanDefinition.getClassName().trim())){  

                    sigletons.put(beanDefinition.getId(),Class.forName(beanDefinition.getClassName()).newInstance() );  

                }  

            } catch (Exception e) {  

                e.printStackTrace();  

            }  

        }  

    }  

  

    /** 

     * 读取xml配置文件 

     */  

    private void readXML(String fileName) {  

        // 创建SAXBuilder对象  

        SAXBuilder saxBuilder = new SAXBuilder();  

  

        try {  

            // 读取资源,获得document对象  

            Document doc = saxBuilder.build(this.getClass().getClassLoader()  

                    .getResourceAsStream(fileName));  

            // 获取根元素  

            Element rootEle = doc.getRootElement();  

            // 从根元素获得所有的子元素,建立元素集合  

            List listBean = XPath.selectNodes(rootEle, "/beans/bean");  

  

            // 遍历根元素的子元素集合,扫描配置文件中的bean  

            for (int i = 0; i < listBean.size(); i++) {  

                 // 将根元素beans下的bean子元素作为一个新的子根元素  

                Element elementBean = (Element) listBean.get(i);  

                //获取id属性值  

                String id = elementBean.getAttributeValue("id");  

                //获取class属性值  

                String clazz = elementBean.getAttributeValue("class");  

                  

                BeanDefinition beanDefine = new BeanDefinition(id,clazz);  

                // 获取子根元素bean下的所有property子元素  

                List listProperty = elementBean.getChildren("property");  

                // 遍历子根元素的子元素集合(即遍历property元素)  

                for (int j = 0; j < listProperty.size(); j++) {  

                    // 获取property元素  

                    Element elmentProperty = (Element)listProperty.get(j);  

                    // 获取name属性值  

                    String propertyName = elmentProperty.getAttributeValue("name");  

                    // 获取ref属性值  

                    String propertyref = elmentProperty.getAttributeValue("ref");  

                      

                    PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName,propertyref);  

                      

                    beanDefine.getPropertys().add(propertyDefinition);  

                }  

                  

                // 将javabean添加到集合中  

                beanDefines.add(beanDefine);  

            }  

        } catch (Exception e) {  

            e.printStackTrace();  

        }  

    }  

  

  

    /** 

     * 获取bean实例 

     */  

    @Override  

    public Object getBean(String beanName) {  

        return this.sigletons.get(beanName);  

    }  

}  

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

[java] view
plain copy

 print?





public interface Service {  

    public void serviceMethod();  

}  

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

 

总结

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

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

        源码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐