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


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


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

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

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

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

      

    简单配置,反射

      

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

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

    <?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试一下。下面我

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

    public interface BeanFactory {
    
    	Object getBean(String id);
    }
    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,为了存放我们的属性值。如下所示:

    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的实例化做进一步的封装了。

    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框架(十一),马

    上送上。


         源码下载


  • 相关阅读:
    ASP计算周开始和一年有多少周及某年第一周开始日期
    http://www.lancen.net/
    JSP的对象
    两个SQL语句
    sql 分頁
    网页特效制作汇总
    存储过程 解密
    一个计算周次和本周时间范围的代码(c#)
    Java试题
    如何在 VS 2005 里调试 Javascript
  • 原文地址:https://www.cnblogs.com/ainima/p/6330965.html
Copyright © 2020-2023  润新知