TinySpring分析二

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中,跟路径就是project下的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,非常easy吧,就是建一个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();

		// 默认是project文件夹
	//	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());
		}

依照使用者与创建者分离的原则,初始化注冊的代码出如今client也不合适;

怎么办?

合起来呗。

还是先写測试代码 例如以下

<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

时间: 2024-11-05 13:38:39

TinySpring分析二的相关文章

netty 源码分析二

以服务端启动,接收客户端连接整个过程为例分析, 简略分为 五个过程: 1.NioServerSocketChannel 管道生成, 2.NioServerSocketChannel 管道完成初始化, 3.NioServerSocketChannel注册至Selector选择器, 4.NioServerSocketChannel管道绑定到指定端口,启动服务 5.NioServerSocketChannel接受客户端的连接,进行相应IO操作 Ps:netty内部过程远比这复杂,简略记录下方便以后回忆

又是正版!Win下ffmpeg源码调试分析二(Step into ffmpeg from Opencv for bugs in debug mode with MSVC)

最近工作忙一直没时间写,但是看看网络上这方面的资源确实少,很多都是linux的(我更爱unix,哈哈),而且很多是直接引入上一篇文章的编译结果来做的.对于使用opencv但是又老是被ffmpeg库坑害的朋友们,可能又爱又恨,毕竟用它处理和分析视频是第一选择,不仅是因为俩者配合使用方便,而且ffmpeg几乎囊括了我所知道的所有解编码器,但是正是因为这个导致了一些bug很难定位,所以有必要考虑一下如何快速定位你的ffmpeg bug. sorry,废话多了.首先给个思路: 1.使opencv 的hi

传奇源码分析-客户端(游戏逻辑处理源分析二)

5.接受登录成功后,接收GameSrv服务器发送的消息:接收GameGate发送的消息:CClientSocket::OnSocketMessage的FD_READ事件中,PacketQ.PushQ((BYTE*)pszPacket);把接收到的消息,压入PacketQ队列中.处理PacketQ队列数据是由CGameProcess::Load()时调用OnTimer在CGameProcess::OnTimer中处理的, 处理过程为:OnMessageReceive; ProcessPacket(

Redis数据持久化机制AOF原理分析二

Redis数据持久化机制AOF原理分析二 分类: Redis 2014-01-12 15:36  737人阅读  评论(0)  收藏  举报 redis AOF rewrite 目录(?)[+] 本文所引用的源码全部来自Redis2.8.2版本. Redis AOF数据持久化机制的实现相关代码是redis.c, redis.h, aof.c, bio.c, rio.c, config.c 在阅读本文之前请先阅读Redis数据持久化机制AOF原理分析之配置详解文章,了解AOF相关参数的解析,文章链

[Android]Volley源码分析(二)Cache

Cache作为Volley最为核心的一部分,Volley花了重彩来实现它.本章我们顺着Volley的源码思路往下,来看下Volley对Cache的处理逻辑. 我们回想一下昨天的简单代码,我们的入口是从构造一个Request队列开始的,而我们并不直接调用new来构造,而是将控制权反转给Volley这个静态工厂来构造. com.android.volley.toolbox.Volley: public static RequestQueue newRequestQueue(Context conte

Android Binder分析二:Natvie Service的注冊

这一章我们通过MediaPlayerService的注冊来说明怎样在Native层通过binder向ServiceManager注冊一个service,以及client怎样通过binder向ServiceManager获得一个service,并调用这个Service的方法. Native Service的注冊 这里以MediaPlayerService举例来说明怎样在Native层注冊Service,首先来看main_mediaservice.cpp的main方法: int main(int a

哇!板球 源码分析二

游戏主页面布局 创建屏下Score标签 pLabel = CCLabelTTF::create("Score", "Arial", TITLE_FONT_SIZE); //分数标签 //设置标签字体的颜色 pLabel->setColor (ccc3(0, 0, 0)); //设置文本标签的位置 pLabel->setPosition ( ccp ( SCORE_X, //X坐标 SCORE_Y //Y坐标 ) ); //将文本标签添加到布景中 this

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

Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 2012-09-07 11:19 8152人阅读 评论(12) 收藏 举报 代码分析android相册优化工作 Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 一 图库数据管理 Gallery2的数据管理 DataManager(职责:管理数据源)- MediaSource(职责:管理数据集) - MediaSet(职责:管理数据项).DataManager中初始化所有的数据源(LocalSo

android原生browser分析(二)--界面篇

我们先看一张浏览器的主界面,上面标示浏览器界面各部分对应的类,这里是以平板上的界面为例.给张图是为了给大家一个直观的感觉. BrowserActivity是整个应用的主界面,在onCreate中创建了Controller对象,Controller对象是整个应用最重要的管理类,这个后面再说. @Override public void onCreate(Bundle icicle) { mController = createController(); } Controller的创建中新建了UI类