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中,跟路径就是工程下的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分析二的更多相关文章
- SNMP报文抓取与分析(二)
SNMP报文抓取与分析(二) SNMP报文抓取与分析(二) 1.SNMP报文表示简介 基本编码规则BER 标识域Tag表示 长度域length表示 2.SNMP报文详细分析(以一个get-respon ...
- Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题
4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...
- yhd日志分析(二)
yhd日志分析(二) 继续yhd日志分析,统计数据 日期 uv pv 登录人数 游客人数 平均访问时长 二跳率 独立ip数 1 分析 登录人数 count(distinct endUserId) 游客 ...
- SQLite入门与分析(二)---设计与概念(续)
SQLite入门与分析(二)---设计与概念(续) 写在前面:本节讨论事务,事务是DBMS最核心的技术之一.在计算机科学史上,有三位科学家因在数据库领域的成就而获ACM图灵奖,而其中之一Jim G ...
- Linux内核启动代码分析二之开发板相关驱动程序加载分析
Linux内核启动代码分析二之开发板相关驱动程序加载分析 1 从linux开始启动的函数start_kernel开始分析,该函数位于linux-2.6.22/init/main.c start_ke ...
- 一些有用的javascript实例分析(二)
原文:一些有用的javascript实例分析(二) 5 求出数组中所有数字的和 window.onload = function () { var oBtn = document.getElement ...
- Android4.0图库Gallery2代码分析(二) 数据管理和数据加载
Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 2012-09-07 11:19 8152人阅读 评论(12) 收藏 举报 代码分析android相册优化工作 Androi ...
- MapReduce深度分析(二)
MapReduce深度分析(二) 五.JobTracker分析 JobTracker是hadoop的重要的后台守护进程之一,主要的功能是管理任务调度.管理TaskTracker.监控作业执行.运行作业 ...
- Java线程池使用和分析(二) - execute()原理
相关文章目录: Java线程池使用和分析(一) Java线程池使用和分析(二) - execute()原理 execute()是 java.util.concurrent.Executor接口中唯一的 ...
随机推荐
- Linux 下不经过BIOS重启(i386)
前段时间有个项目,要求在Linux下不经过BIOS重启,i386平台. 一.可行性分析 众所周知,BIOS中包含了CPU及其他各种设备的初始化代码,Linux系统运行之后是否能够将各种用到的设备返回到 ...
- 【SSH系列】spring中为什么要使用IOC
开篇前言 在前面的博文中,小编主要简单的介绍了spring的入门知识,随着学习的深入,我们知道spring最核心的两大技术,IOC和AOP,这两个技术也是spring最耀眼的地方,在后续的博文中小编将 ...
- Scala:提取器(Extractor)
http://blog.csdn.net/pipisorry/article/details/52902671 提取器是从传递给它的对象中提取出构造该对象的参数. Scala 标准库包含了一些预定义的 ...
- Android基础知识点-Manifest清单文件
每个应用的根目录中都必须包含一个 AndroidManifest.xml 文件(且文件名精确无误). 清单文件向 Android 系统提供应用的必要信息,系统必须具有这些信息方可运行应用的任何代码. ...
- 自定义一个View作为弹出对话框
public void dialog(){ //获得布局对象 View view = LayoutInflater.from(getActivity()).inflate(R.layout.dialo ...
- collection 中对类排序
首先 写出 一个person类 让他继承Comparable 构造函数和get/set不用说 我们要覆盖父类中的comparto方法 代码如下 省略get/set package a; public ...
- 阻尼回弹效果的ScrollView嵌套GridView
以前写过一篇带阻尼回弹效果的ScrollView,但是有些小问题,于是又重新整理了一下,这篇文章一是一个带阻尼的Scrollview,再个就是Scrollview嵌套GridView实现,而GridV ...
- EBS开发常用编译命令
一.编译FORM 1.将脚本写成shell脚本 cd $AU_TOP/forms/ZHS export FORMS_PATH=.:$FORMS_PATH:$AU_TOP/forms/ZHS frmcm ...
- Android 访问assets下的文件
assets下经常可以放一些比较大的资源,对于这些资源我们如何访问. 步骤 1.获取AssetManager. AssetManager am = getResources().getAssets() ...
- 4.关于QT中的QFile文件操作,QBuffer,Label上添加QPixmap,QByteArray和QString之间的区别,QTextStream和QDataStream的区别,QT内存映射(
新建项目13IO 13IO.pro HEADERS += \ MyWidget.h SOURCES += \ MyWidget.cpp QT += gui widgets network CON ...