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

【SSH进阶之路】一步步重构容器实现Spring框架——配置文件+反射实现IoC容器(十)

2017-04-20 22:05 706 查看
目录

     【SSH进阶之路】一步步重构容器实现Spring框架——从一个简单的容器开始(八)

     【SSH进阶之路】一步步重构容器实现Spring框架——解决容器对组件的“侵入式”管理的两种方案--主动查找和控制反转(九)

     【SSH进阶之路】一步步重构容器实现Spring框架——配置文件+反射实现IoC容器(十)

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

       上上篇博文【SSH进阶之路】一步步重构容器实现Spring框架——从一个简单的容器开始(八),我们为了去掉接

口对具体实现的依赖关系,封装了一个特别简陋的容器。

       上篇博文【SSH进阶之路】一步步重构容器实现Spring框架——解决容器对组件的“侵入式”管理的两种方案--主

动查找和控制反转(九),我们利用控制反转,去掉了组件对容器的依赖。

  

简单配置,反射

  

       上篇博文容器初始化时,使用new的方式来实力化对象,这篇博文我们利用配置文件+反射实力化对象,进一步封

装降低容器和组件的耦合度。下面我们先看一下配置文件。

[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" />  

      

</beans>  

      看到上面的配置文件,除了命名空间没有,和spring的配置文件已经很像了,下面我们就使用dom4j或jdom来读取

配置文件,并将配置文件中配置类利用反射实例化。本实例我们使用的jdom,大家也可以使用dom4j试一下。下面我

们看一下读取配置文件的代码:

[java] view
plain copy

 print?

public interface BeanFactory {  

  

    Object getBean(Strin
24000
g id);  

}  

[java] view
plain copy

 print?

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;  

  

import com.tgb.container.dao.Dao;  

import com.tgb.container.service.Service;  

  

/** 

 * 从类路径加载配置文件 

 *  

 * @author liang 

 *  

 */  

public class ClassPathXmlApplicationContext implements BeanFactory {  

  

    // 用于存放Bean  

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

  

    public ClassPathXmlApplicationContext(String fileName) {  

  

        this.readXML(fileName);  

  

    }  

  

    // 解析xml文件,通过反射将配置的beasn放到container中,并实现依赖注入  

    private void readXML(String fileName) {  

        // 创建SAXBuilder对象  

        SAXBuilder saxBuilder = new SAXBuilder();  

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

        Document doc;  

        try {  

            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++) {  

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

                // 获取id属性值  

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

                // 获取class属性值  

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

                // 反射,实例化  

                Object o = Class.forName(clazz).newInstance();  

                beans.put(id, o);  

            }  

  

            // 依赖管理,这里还不灵活,但是原理是一样的  

            Service service = (Service) beans.get("service");  

            Dao dao = (Dao) beans.get("dao");  

            // 依赖注入,Service实现依赖dao的实现  

            service.setDao(dao);  

  

        } catch (Exception e) {  

  

            e.printStackTrace();  

        }  

    }  

  

    /** 

     * 查找组件 

     *  

     * @param id 

     * @return 

     */  

    @Override  

    public Object getBean(String id) {  

        return beans.get(id);  

    }  

}  

     看到上面的代码,我们发现读取配置文件的方法中包含了反射,代码的可读性太差,并且对面向对象的封装不够彻

底,下面我们将bean的实例化以及依赖注入进行进一步的封装。

封装bean的实例化

       为了做进一步的封装,我们将配置文件的属性封装成一个javabean,为了存放我们的属性值。如下所示:

[java] view
plain copy

 print?





public class BeanDefinition {  

  

    private String id;  

    private String className;  

  

      

    public BeanDefinition(String id, String className) {  

        this.id = id;  

        this.className = className;  

    }  

  

    public String getId() {  

        return id;  

    }  

  

    public void setId(String id) {  

        this.id = id;  

    }  

  

    public String getClassName() {  

        return className;  

    }  

  

    public void setClassName(String className) {  

        this.className = className;  

    }  

  

}  

     现在我们就可以把bean的实例化做进一步的封装了。

[java] view
plain copy

 print?





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;  

  

import com.tgb.container.dao.Dao;  

import com.tgb.container.service.Service;  

  

/** 

 * 容器 

 *  

 * @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() {  

        Service service = (Service) this.sigletons.get("service");  

        Dao dao = (Dao) this.sigletons.get("dao");  

        //依赖注入,Service实现依赖dao的实现  

        service.setDao(dao);  

    }  

  

    /** 

     * 完成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++) {  

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

                // 获取id属性值  

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

                // 获取class属性值  

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

                  

                BeanDefinition beanDefine = new BeanDefinition(id,clazz);  

                // 将javabean添加到集合中  

                beanDefines.add(beanDefine);  

            }  

        } catch (Exception e) {  

            e.printStackTrace();  

        }  

    }  

  

  

    /** 

     * 获取bean实例 

     */  

    @Override  

    public Object getBean(String beanName) {  

        return this.sigletons.get(beanName);  

    }  

  

}  

      我们知道容器不仅负责创建对象,而且可以管理对象的依赖关系,管理对象的生命周期等等。我们仅实现了容器

灵活创建对象的部分,依赖注入部分是由我们手动注入的。 对象的依赖关系还不灵活,但是我们已经能够看到IoC的

影子了,只是形似,还没有达到神似的目标。

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

上送上。

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