step5

看完了前面的几步,到现在我们必然要想到的问题就是,数据要是放在xml中怎么读?

其实按照正常思维一步一步来,从xml中读数据和之前手工配进去并没有什么大的区别,只要读出来就OK了。

先看测试程序,

	public void Step5() throws Exception {
		// 1.读取配置
		XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader();
		xmlBeanDefinitionReader.loadBeanDefinitions("bin/resources/tinyioc.xml");

		// 2.初始化BeanFactory并注册bean
		BeanFactory beanFactory = new AbstractBeanFactory();
		for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getBeanDefinitionMap().entrySet()) {
		        ((AbstractBeanFactory)beanFactory).registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
		}

		// 3.获取bean
		HelloWorldServiceImpl helloWorldService = (HelloWorldServiceImpl) beanFactory.getBean("helloWorldService");
		helloWorldService.helloWorld3();
	}

关于路径问题

在java中,获取文件(包括xml,jpg等等)有两种方式

Class类下的getResource(String path)方法与

ClassLoader类下的getResource(String path)方法





先说后面一种,ClassLoader.getResource()参数中不带"/",默认就是根路径(在Eclipse中,跟路径就是工程下的bin文件夹,在默认情况下,eclipse会把项目中的src下的内容拷贝到bin下,因此也可以理解为根目录就是src目录)



第一种Class.getResource()可以带"/"也可以不带

一旦带了/ 就默认从根路径(就是bin 就是src)下查找了

如果没有/ 就从这个类本身的那个路径下查找

详细资料见

http://www.cnblogs.com/yejg1212/p/3270152.html

在step5这个例子里

InputStream is = new FileInputStream(local);这里的local是从项目目录算的,因此还得加上bin





看了测试代码大家就会知道,我们的程序结构了吧,XmlBeanDefinitionReader的主要作用就是读取xml,然后转换成一个个BeanDefinition,再存储进BeanDefinitionMap,再创建一个BeanFactory,将BeanDefinitionMap中的记录一个一个再注册一边。

public class XmlBeanDefinitionReader {

	//bean清单 就是前面说的学校里面的学生信息表
	private Map<String, BeanDefinition> beanDefinitionMap;

	public XmlBeanDefinitionReader(){
		beanDefinitionMap = new HashMap<String, BeanDefinition>();
	}

	public void loadBeanDefinitions(String local) throws IOException, ParserConfigurationException, SAXException {
		InputStream is = new FileInputStream(local);
		parseNode(is);
	}

看了loadBeanDefinitions,很简单吧,就是建一个InputStream,连接到文件上,然后从文件中读数据。

这里面的东西不难,但是比较繁杂,牵扯最多的就是对xml的解析

相关知识见

http://blog.csdn.net/dlf123321/article/details/39649089

/**
	 * 通过InputStream 获得每一个bean
	 * @param is
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 */
	public void parseNode(InputStream is) throws ParserConfigurationException, SAXException, IOException {
		DocumentBuilderFactory domfac = DocumentBuilderFactory.newInstance();
		DocumentBuilder domBuilder = domfac.newDocumentBuilder();

		// 默认是工程目录
	//	InputStream is = new FileInputStream("bin/resources/tinyioc.xml");
		Document doc = domBuilder.parse(is);
		Element root = doc.getDocumentElement();
		NodeList beans = root.getChildNodes();
		for (int i = 0; i < beans.getLength(); i++)
			if (beans.item(i) instanceof Element) {
				Element el=(Element)beans.item(i);
				parseElement(el);
			}
		is.close();

	}

	/**
	 * 分析每一个bean的id class
	 * @param el
	 */
	public void parseElement(Element el){
		String id=el.getAttribute("id");
		String classPath=el.getAttribute("class");
	//	System.out.println(id+"  "+classPath);
		BeanDefinition bd=new BeanDefinition();
		bd.setBeanClassName(classPath);
		parseProperties(el,bd);
		beanDefinitionMap.put(id, bd);
	}

	/**
	 * 分析每一个bean的参数  并加入到beandefinition的property里面
	 * @param el
	 * @param bd
	 */
	public void parseProperties(Element el,BeanDefinition bd){
		NodeList bl=el.getElementsByTagName("property");
		for (int i = 0; i < bl.getLength(); i++)
			if (bl.item(i) instanceof Element) {
				Element property=(Element)bl.item(i);
				String name=property.getAttribute("name");
    		//	System.out.print("   "+name+"  ");
				if (property.getAttribute("ref")!="") {
					BeanReference br=new BeanReference(property.getAttribute("ref"));
					PropertyValue pV=new PropertyValue(name,br);
					bd.getPropertyValues().addPropertyValue(pV);
			//		System.out.println("   "+br.getName()+"  ");
				}
				if (property.getAttribute("value")!="") {
					String value=property.getAttribute("value");
					PropertyValue pV=new PropertyValue(name, value);
					bd.getPropertyValues().addPropertyValue(pV);
				//	System.out.println(value);
				}
			}

	}

	public Map<String, BeanDefinition> getBeanDefinitionMap() {
		return beanDefinitionMap;
	}

再剩下的代码,参考step4就ok

step6

如果仔细,比对XmlBeanDefinitionReader与AbstractBeanFactory,就能发现两个类里面都有beanDefinitionMap,重写两边,不合适。

另外在step5中

		// 2.初始化BeanFactory并注册bean
		BeanFactory beanFactory = new AbstractBeanFactory();
		for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getBeanDefinitionMap().entrySet()) {
		        ((AbstractBeanFactory)beanFactory).registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
		}

按照使用者与创建者分离的原则,初始化注册的代码出现在客户端也不合适;

怎么办?

合起来呗。

还是先写测试代码 如下

<pre name="code" class="java">public void Step7() throws Exception {
		ApplicationContext ac=new ApplicationContext("bin/resources/tinyioc.xml");
		HelloWorldServiceImpl helloWorldService = (HelloWorldServiceImpl) ac.getBean("helloWorldService");
		helloWorldService.helloWorld3();
	}

漂亮!关键就是ApplicationContext,上面已经说了,要把XmlBeanDefinitionReader与AbstractBeanFactory合起来,也就是说要把getBean与loadBeanDefinitions装到一个类里面去

package com.myspring.context;

import java.util.Map;

import com.bjsxt.spring.BeanFactory;
import com.myspring.beans.BeanDefinition;
import com.myspring.beans.factory.AbstractBeanFactory;
import com.myspring.beans.xml.XmlBeanDefinitionReader;

public class ApplicationContext implements BeanFactory {

	private AbstractBeanFactory abf=new AbstractBeanFactory();

	public  ApplicationContext(String local) throws Exception {
	//	InputStream is = new FileInputStream(local);
		loadBeanDefinitions(abf,local);
	}

	protected void loadBeanDefinitions(AbstractBeanFactory beanFactory,String configLocation) throws Exception {
		XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader();
		xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);
		for (Map.Entry<String, BeanDefinition> beanDefinitionEntry :
			xmlBeanDefinitionReader.getBeanDefinitionMap().entrySet()) {
			beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
		}
	}
	@Override
	public Object getBean(String id) {
		// TODO Auto-generated method stub
		Object obj=null;
		try {
			obj = abf.getBean(id);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return obj;
	}
}

AbstractBeanFactory与ApplicationContext都继承了BeanFactory,然后我们不直接用BeanFactory,而是让ApplicationContext中装一个AbstractBeanFactory,这不就是最简单的代理模式么?

代码到这里,就算是完成了黄亿华大神的TinySpring中IoC的大部分代码

之所以说是大部分,也就是说现在大家看到的代码还有一些部分与TinySpring不同

主要在这几个方面

1 Resources部分

  在我完成的代码里,读取xml的时候直接就是一个InputStream,TinySpring的方式是有一个Resource类,同时还有一个LoadResource类用来加载资源,当然实现的内部机理都是inputstream;

2 接口问题

  我一直认为,良好的代码是一次一次重构出来的,依我现在的水平,确实不能够很清晰地说出,分了那么多层接口,抽象类的实际作用,因此在我的代码里各个部分都很"薄弱"(只有一层)

3 对于类的加载,有两种方式一种直接加载,一种延迟加载,TinySpring最开始的那几个step还是在getBean的时候才newInstance的,但是到后面

	protected void onRefresh() throws Exception{
	     beanFactory.preInstantiateSingletons();
	  }

	public void preInstantiateSingletons() throws Exception {
		for (Iterator<String> it = this.beanDefinitionNames.iterator(); it.hasNext();) {
			String beanName = (String) it.next();
			getBean(beanName);
		}
	}

所以的类都直接加载了;





4 单例模式

TinySpring中一个bean默认只会加载一次,第二次getBean()的时候会取出之前已经creat的那个;

public Object getBean(String name) throws Exception {
		BeanDefinition beanDefinition = beanDefinitionMap.get(name);
		if (beanDefinition == null) {
			throw new IllegalArgumentException("No bean named " + name + " is defined");
		}
		Object bean = beanDefinition.getBean();
		if (bean == null) {                     //******************查找beanDefinition
			bean = doCreateBean(beanDefinition);
            bean = initializeBean(bean, name);
            beanDefinition.setBean(bean);
		}
		return bean;
	}

	protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
		Object bean = createBeanInstance(beanDefinition);
		beanDefinition.setBean(bean);            //******************写入beanDefinition
		applyPropertyValues(bean, beanDefinition);
		return bean;
	}

我写的代码中,没有上面的步骤,因此即使第二次get一个已经get过得bean,仍然会产生一个新的bena!

我写的代码 下载地址

http://download.csdn.net/detail/dlf123321/7992633

参考资料

http://www.cnblogs.com/yejg1212/p/3270152.html

http://blog.csdn.net/dlf123321/article/details/39649089

TinySpring分析二的更多相关文章

  1. SNMP报文抓取与分析(二)

    SNMP报文抓取与分析(二) SNMP报文抓取与分析(二) 1.SNMP报文表示简介 基本编码规则BER 标识域Tag表示 长度域length表示 2.SNMP报文详细分析(以一个get-respon ...

  2. Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题

    4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...

  3. yhd日志分析(二)

    yhd日志分析(二) 继续yhd日志分析,统计数据 日期 uv pv 登录人数 游客人数 平均访问时长 二跳率 独立ip数 1 分析 登录人数 count(distinct endUserId) 游客 ...

  4. SQLite入门与分析(二)---设计与概念(续)

    SQLite入门与分析(二)---设计与概念(续)   写在前面:本节讨论事务,事务是DBMS最核心的技术之一.在计算机科学史上,有三位科学家因在数据库领域的成就而获ACM图灵奖,而其中之一Jim G ...

  5. Linux内核启动代码分析二之开发板相关驱动程序加载分析

    Linux内核启动代码分析二之开发板相关驱动程序加载分析 1 从linux开始启动的函数start_kernel开始分析,该函数位于linux-2.6.22/init/main.c  start_ke ...

  6. 一些有用的javascript实例分析(二)

    原文:一些有用的javascript实例分析(二) 5 求出数组中所有数字的和 window.onload = function () { var oBtn = document.getElement ...

  7. Android4.0图库Gallery2代码分析(二) 数据管理和数据加载

    Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 2012-09-07 11:19 8152人阅读 评论(12) 收藏 举报 代码分析android相册优化工作 Androi ...

  8. MapReduce深度分析(二)

    MapReduce深度分析(二) 五.JobTracker分析 JobTracker是hadoop的重要的后台守护进程之一,主要的功能是管理任务调度.管理TaskTracker.监控作业执行.运行作业 ...

  9. Java线程池使用和分析(二) - execute()原理

    相关文章目录: Java线程池使用和分析(一) Java线程池使用和分析(二) - execute()原理 execute()是 java.util.concurrent.Executor接口中唯一的 ...

随机推荐

  1. Ubuntu14下安装svn仓库,以及权限配置

    sudo apt-get update 接下来安装svn apt-get install subversionapt-get install libapache2-svn 检查svn是否安装成功了: ...

  2. DragVideo,一种在播放视频时,可以任意拖拽的方案

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53638896 前言 项目已开源到 ...

  3. 28 自定义View流式布局

    流式布局每行的行高以本行中最高的元素作为高,如果一个元素放不下到一行时直接到第二行 FlowLayoutView package com.qf.sxy.customview05.widget; imp ...

  4. SSH 之 Spring的源码(二)——Bean实例化

    首先来看一段代码,看过上一节的朋友肯定对这段代码并不陌生.这一段代码诠释了Spring加载bean的完整过程,包括读取配置文件,扫描包,加载类,实例化bean,注入bean属性依赖. <span ...

  5. java泛型总结(类型擦除、伪泛型、陷阱)

    JDK1.5开始实现了对泛型的支持,但是java对泛型支持的底层实现采用的是类型擦除的方式,这是一种伪泛型.这种实现方式虽然可用但有其缺陷. <Thinking in Java>的作者 B ...

  6. Android Multimedia框架总结(四)MediaPlayer中从Java层到C++层类关系及prepare及之后其他过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自:http://blog.csdn.net/hejjunlin/article/details/52420803 前言:在上篇中,分析了MediaPl ...

  7. Ajax框架,DWR介绍,应用,例子

    使用Ajax框架 1. 简化JavaScript的开发难度 2. 解决浏览器的兼容性问题 3. 简化开发流程 常用Ajax框架 Prototype 一个纯粹的JavaScript函数库,对Ajax提供 ...

  8. 什么时候App委托会收到App进程被结束的消息

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们在Xcode建立的新项目后,在AppDelegate类会发 ...

  9. 【Netty源码分析】ChannelPipeline(二)

    在上一篇博客[Netty源码学习]ChannelPipeline(一)中我们只是大体介绍了ChannelPipeline相关的知识,其实介绍的并不详细,接下来我们详细介绍一下ChannelPipeli ...

  10. 【编程练习】poj1068

    Parencodings Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 24202   Accepted: 14201 De ...