参考:Tiny Spring 分析一,原文:1000行代码读懂Spring(一)- 实现一个基本的IoC容器

代码地址:https://github.com/xiaoxicode/jdk_source_1.7/tree/master/tinyspring


特此声明,本文不能算严格意义上的原创,只能算是黄文章的再次解读吧。
开工
如下的代码不需要解释了吧。

step1

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.myspring.factory;  
  2.   
  3.   
  4. public interface BeanFactory {  
  5.     Object getBean(String name) throws Exception;  
  6. }  
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.myspring.bean;  
  2.   
  3.   
  4. /**  
  5.  * bean的内容及元数据,保存在BeanFactory中,包装bean的实体  
  6.  */  
  7. public class BeanDefinition {  
  8.   
  9.     private Object bean;  
  10.     private Class<?> beanClass;  
  11.     private String beanClassName;  
  12.     public BeanDefinition() {     
  13.     }  
  14.     public BeanDefinition(Object object){  
  15.         this.bean=object;  
  16.     }  
  17.   
  18.     public void setBeanClassName(String beanClassName) {  
  19.         this.beanClassName = beanClassName;  
  20.         try {  
  21.             this.beanClass = Class.forName(beanClassName);  
  22.         } catch (ClassNotFoundException e) {  
  23.             e.printStackTrace();  
  24.         }  
  25.     }  
  26.     //省略部分get/set方法  
  27. }  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.myspring.factory;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Iterator;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7. import java.util.concurrent.ConcurrentHashMap;  
  8.   
  9. import com.myspring.bean.BeanDefinition;  
  10.   
  11. public class AbstractBeanFactory implements BeanFactory {  
  12.           
  13.     //存放Factory里的所有bean的详细信息  
  14.     //可以理解为Factory里面的bean的信息表  
  15.     //就像一个学校总会有一个学生信息表  
  16.     private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();  
  17.     //存放Factory里的所有bean的name  
  18.     private final List<String> beanDefinitionNames = new ArrayList<String>();  
  19.   
  20.   
  21.     @Override  
  22.     public Object getBean(String name) throws Exception {  
  23.         BeanDefinition beanDefinition = beanDefinitionMap.get(name);  
  24.         if (beanDefinition == null) {  
  25.             throw new IllegalArgumentException("No bean named " + name + " is defined");  
  26.         }  
  27.         Object bean = beanDefinition.getBean();   
  28.         return bean;  
  29.     }  
  30.       
  31.     /** 
  32.     *将新加入的beanDefinition注册到beanDefinitionMap里 
  33.     *这里只是将beanDefinition的定义放入"注册表"(beanDefinitionMap) 至于beanDefinition是否有错误 以后再说 这里不管 
  34.     **/  
  35.     public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception {  
  36.         beanDefinitionMap.put(name, beanDefinition);  
  37.         beanDefinitionNames.add(name); //为什么现在不检测beanDefinition的细节 例如有没有bean? layzload  
  38.     }  
  39. }  

来测试一下,以HelloWorldServiceImpl为例
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.myspring;  
  2.   
  3.   
  4. public class HelloWorldServiceImpl {  
  5.   
  6.         public void helloWorld2() {  
  7.             System.out.println("hello");  
  8.     }  
  9. }  

测试代码如下
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public void Step1() throws Exception {  
  2.         BeanFactory beanFactory=new AbstractBeanFactory();  
  3.         BeanDefinition beanDefinition=new BeanDefinition(new HelloWorldServiceImpl());  
  4.         ((AbstractBeanFactory)beanFactory).registerBeanDefinition("helloworld",beanDefinition);  
  5.           
  6.         HelloWorldServiceImpl h=(HelloWorldServiceImpl) beanFactory.getBean("helloworld");  
  7.         h.helloWorld2();  
  8.     }  
很简单,打印出了hello;
ok 至此 我们最简单的IoC就搭建完成了。
现在我们就一步一步地完善我们的容器

step2

第一步的时候,beanDefinition里面我们直接放入了bean,向下面这个,我们放入classname会如何?
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Test  
  2.     public void Step2() throws Exception {  
  3.         BeanFactory beanFactory=new AbstractBeanFactory();  
  4.         BeanDefinition beanDefinition=new BeanDefinition();  
  5.         beanDefinition.setBeanClassName("com.myspring.HelloWorldServiceImpl");  
  6.         ((AbstractBeanFactory)beanFactory).registerBeanDefinition("helloworld",beanDefinition);  
  7.           
  8.         HelloWorldServiceImpl h=(HelloWorldServiceImpl) beanFactory.getBean("helloworld");  
  9.         h.helloWorld2();  
  10.     }  

解决办法很简单,在AbstractBeanFactory/getBean()方法返还bean之前加上如下代码即可。
if (bean==null) {
     bean=beanDefinition.getBeanClass().newInstance();

}

step3

继续走,如果我们在HelloWorldServiceImpl里面有简单的参数怎么办,示意代码如下
private String text;
private int    a;

public void helloWorld(){
System.out.println(text+a+" ss");
}
既然有参数,那我们就设计一个PropertyValue
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.myspring.bean;  
  2.   
  3.   
  4. /** 
  5.  * 用于bean的属性注入 
  6.  */  
  7. public class PropertyValue {  
  8.     private final String name;  
  9.     private final Object value;  // 省略get/set  后文对简单的get/set方法将直接省略 不再说明  
  10. }  

下来就是在BeanDefinition里面增加一个List<PropertyValue> pvs=new ArrayList<PropertyValue>,毕竟不能限制一个类只有一个属性吧。
一个类中不会只有一个参数,那必然就是List了。好像说的有道理,目前我们是人为地给pvs里面加数据,用add()方法,如果一个类中,有重复的属性呢?
开玩笑,java里能出现两个变量同名吗?
当然java类里是不存在的,可我们得知道成型的spring可是从xml里面读取数据的
如果我写成这样 怎么办?
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <bean id="userService" class="com.bjsxt.services.UserService" >  
  2.      <property name="userDao" bean="u" />  
  3.      <property name="userDao" bean="u" />  
  4. </bean>  
因此我们得再加入一个类PropertyValues
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.myspring.bean;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. /** 
  7.  * 包装一个对象所有的PropertyValue。<br/> 
  8.  * 为什么封装而不是直接用List?因为可以封装一些操作。 
  9.  */  
  10. public class PropertyValues {  
  11.   
  12.   
  13.     private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();  
  14.     public PropertyValues() {  
  15.     }  
  16.   
  17.     public void addPropertyValue(PropertyValue pv) {  
  18.         //TODO:这里可以对于重复propertyName进行判断,直接用list没法做到  
  19.     //  System.out.println(pv.getName()+pv.getValue());  
  20.         this.propertyValueList.add(pv);  
  21.     }  
  22.     public List<PropertyValue> getPropertyValues() {  
  23.         return this.propertyValueList;  
  24.     }  
  25. }  
因而在BeanDefinition里加入private PropertyValues propertyValues;即可
相应的getBean方法也要变
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2.     public Object getBean(String name) throws Exception {  
  3.         BeanDefinition beanDefinition = beanDefinitionMap.get(name);  
  4.         if (beanDefinition == null) {  
  5.             throw new IllegalArgumentException("No bean named " + name  
  6.                     + " is defined");  
  7.         }  
  8.         Object bean = beanDefinition.getBean();  
  9.         if (bean == null) {  
  10.             bean = beanDefinition.getBeanClass().newInstance();  
  11.         }  
  12.         creatBean(bean, beanDefinition); // 可不可以只传一个beandefinition  
  13.                                             // 在方法里在beanDefinition.getBean();  
  14.                                             // 这样还可以少传递一个对象呢?  
  15.         return bean;  
  16.     }  
大家看到了关键问题在creatBean方法上
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1.     public void creatBean(Object bean, BeanDefinition beanDefinition)  
  2.             throws Exception {  
  3.         if (beanDefinition.getPropertyValues() != null)  
  4.             creatBeanWithProperty(bean, beanDefinition);  
  5.     }  
  6.   
  7.    public void creatBeanWithProperty(Object bean, BeanDefinition beanDefinition) throws Exception{  
  8.           
  9.              
  10.             int size =beanDefinition.getPropertyValues().getPropertyValues().size();  
  11.             List<PropertyValue> list = beanDefinition.getPropertyValues().getPropertyValues();  
  12.             for (int i = 0; i <size ; i++) {  
  13.                   
  14.                 //到底是不是引用类型 得区别开  
  15.                 //不区别行不行?  
  16.                 if(list.get(i).getValue() instanceof BeanReference){  
  17.                     String beanName=((BeanReference)list.get(i).getValue()).getName();  
  18.                 //    System.out.println("par "+list.get(i).getName());  
  19.                     Object referenceBean=getBean(beanName);  
  20.                     String ms="set"+Character.toUpperCase(list.get(i).getName().charAt(0))+list.get(i).getName().substring(1);  
  21.                   
  22.                     Method m=bean.getClass().getDeclaredMethod(ms, referenceBean.getClass());  
  23.                     m.invoke(bean, referenceBean);  
  24.                 }  
  25.                 else {  
  26.                     String fieldName = list.get(i).getName();  
  27.                     Object value = list.get(i).getValue();  
  28.                     Field field = bean.getClass().getDeclaredField(fieldName); // getDeclaredField是获得所有的字段(不仅仅是public)  
  29.                     field.setAccessible(true); // 这一步必须有  
  30.                     field.set(bean, value);  
  31.                     field.setAccessible(false); // 这一步必须有  
  32.                 }  
  33.             }  
  34.           
  35.     }  
ok,看看测试代码
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public void Step3() throws Exception {  
  2.         // 1.初始化beanfactory  
  3.         BeanFactory beanFactory = new AbstractBeanFactory();  
  4.   
  5.   
  6.         // 2.bean定义  
  7.         BeanDefinition beanDefinition = new BeanDefinition();  
  8.         beanDefinition.setBeanClassName("com.myspring.HelloWorldServiceImpl");  
  9.   
  10.   
  11.         // 3.设置属性  
  12.         PropertyValues propertyValues = new PropertyValues();  
  13.         propertyValues.addPropertyValue(new PropertyValue("text","Hello World!"));  
  14.         propertyValues.addPropertyValue(new PropertyValue("a",new Integer(15)));  
  15.         beanDefinition.setPropertyValues(propertyValues);  
  16.   
  17.   
  18.         // 4.注册bean  
  19.         ((AbstractBeanFactory)beanFactory).registerBeanDefinition("helloworld", beanDefinition);  
  20.   
  21.   
  22.         HelloWorldServiceImpl h = (HelloWorldServiceImpl) beanFactory  
  23.                 .getBean("helloworld");  
  24.         h.helloWorld();  
  25.     }  

测试结果
Hello World!15 ss

step4

上面的类里面的成员变量依然是int,double等的基本变量(String 在这里也算基本变量),如果我在类里面加一个引用变量呢?

如下
private OutputService out;
public void helloWorld3(){
     out.output(text);
    }
OutputService的output方法很简单就是输出text的内容。
那么下来,理所应当的我们会设计出一个参考类
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.myspring;  
  2.   
  3. public class BeanReference {  
  4.     private String name;       
  5.     private Object bean;  
  6. }  

对于BeanReference,我们可以按下面的方式使用
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public void Step4() throws Exception {  
  2.     // 1.初始化beanfactory  
  3.     BeanFactory beanFactory = new AbstractBeanFactory();  
  4.   
  5.   
  6.     // 2.bean定义  
  7.     BeanDefinition beanDefinition = new BeanDefinition();  
  8.     beanDefinition.setBeanClassName("com.myspring.HelloWorldServiceImpl");  
  9.       
  10.     BeanDefinition beanDefinition2 = new BeanDefinition();  
  11.     beanDefinition2.setBeanClassName("com.myspring.OutputService");  
  12.       
  13.     BeanReference beanReference=new BeanReference("outPutService");  
  14.     beanReference.setBean(beanDefinition2);  
  15.   
  16.   
  17.     // 3.设置属性  
  18.     PropertyValues propertyValues = new PropertyValues();  
  19.     propertyValues.addPropertyValue(new PropertyValue("text","Hello World! with referencebean"));  
  20.     propertyValues.addPropertyValue(new PropertyValue("a",new Integer(15)));  
  21.     propertyValues.addPropertyValue(new PropertyValue("out",beanReference));  
  22.     beanDefinition.setPropertyValues(propertyValues);  
  23.   
  24.   
  25.     // 4.注册bean  
  26.     ((AbstractBeanFactory)beanFactory).registerBeanDefinition("helloworld", beanDefinition);  
  27.     ((AbstractBeanFactory)beanFactory).registerBeanDefinition("out", beanDefinition2);  
  28.   
  29.   
  30.     HelloWorldServiceImpl h = (HelloWorldServiceImpl) beanFactory  
  31.             .getBean("helloworld");  
  32.     h.helloWorld3();  
  33. }  


看到第四步注册bean的时候,大家应该想到如果有n个bean,我就得调用registerBeanDefinition方法n次吗?
目前就只能是这个方法了,技术用for循环,beanDefinition的名字也没办法,现在毕竟是模拟,各个变量的名字都是由人输入的,以后会从xml中读,就简单多了。
下面的麻烦的代码大家应该也能猜处理,就是creatBean部分。
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int size =beanDefinition.getPropertyValues().getPropertyValues().size();  
  2. for (int i = 0; i <size ; i++) {  
  3.                 List<PropertyValue> list = beanDefinition.getPropertyValues().getPropertyValues();  
  4.                 //到底是不是引用类型 得区别开  
  5.                 //不区别行不行?  
  6.                 if(list.get(i).getValue() instanceof BeanReference){  
  7.                     String beanName=list.get(i).getName();  
  8.                     Object referenceBean=getBean(beanName);           //循环调用getBean  
  9.                     String ms="set"+Character.toUpperCase(beanName.charAt(0))+beanName.substring(1);  
  10.                   
  11.                       
  12.                     Method m=bean.getClass().getDeclaredMethod(ms, referenceBean.getClass());  
  13.                     m.invoke(bean, referenceBean);  
  14.                       
  15.                 }  
  16.                 else {  
  17.                     String fieldName = list.get(i).getName();  
  18.                     Object value = list.get(i).getValue();  
  19.                     Field field = bean.getClass().getDeclaredField(fieldName); // getDeclaredField是获得所有的字段(不仅仅是public)  
  20.                     field.setAccessible(true); // 这一步必须有  
  21.                     field.set(bean, value);  
  22.                     field.setAccessible(false); // 这一步必须有  
  23.                 }  
  24.               
  25.             }  

还是上面的问题,如果不区分是引用类型还是基本类型可以不?
property里面的value是object类型的,如果我们给里面放的是int,直接set到bean里面,可是这个object要是BeanReference呢,还得取出BeanReference里面的value,然后在循环getbean()。你们说不区分能行吗?
测试结果
Hello World! with referencebean

step5

看完了前面的几步,到现在我们必然要想到的问题就是,数据要是放在xml中怎么读?
其实按照正常思维一步一步来,从xml中读数据和之前手工配进去并没有什么大的区别,只要读出来就OK了。
先看测试程序,
[java]  view plain  copy
  1. public void Step5() throws Exception {  
  2.     // 1.读取配置  
  3.     XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader();  
  4.     xmlBeanDefinitionReader.loadBeanDefinitions("bin/resources/tinyioc.xml");  
  5.        
  6.     // 2.初始化BeanFactory并注册bean  
  7.     BeanFactory beanFactory = new AbstractBeanFactory();  
  8.     for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getBeanDefinitionMap().entrySet()) {  
  9.             ((AbstractBeanFactory)beanFactory).registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());  
  10.     }  
  11.        
  12.     // 3.获取bean  
  13.     HelloWorldServiceImpl helloWorldService = (HelloWorldServiceImpl) beanFactory.getBean("helloWorldService");  
  14.     helloWorldService.helloWorld3();  
  15. }  

关于路径问题
在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中的记录一个一个再注册一边。

[java]  view plain  copy
  1. public class XmlBeanDefinitionReader {  
  2.   
  3.     //bean清单 就是前面说的学校里面的学生信息表  
  4.     private Map<String, BeanDefinition> beanDefinitionMap;  
  5.           
  6.     public XmlBeanDefinitionReader(){  
  7.         beanDefinitionMap = new HashMap<String, BeanDefinition>();  
  8.     }  
  9.   
  10.     public void loadBeanDefinitions(String local) throws IOException, ParserConfigurationException, SAXException {  
  11.         InputStream is = new FileInputStream(local);  
  12.         parseNode(is);  
  13.     }  


看了loadBeanDefinitions,很简单吧,就是建一个InputStream,连接到文件上,然后从文件中读数据。
这里面的东西不难,但是比较繁杂,牵扯最多的就是对xml的解析
相关知识见
http://blog.csdn.net/dlf123321/article/details/39649089

[java]  view plain  copy
  1. /** 
  2.      * 通过InputStream 获得每一个bean 
  3.      * @param is 
  4.      * @throws ParserConfigurationException 
  5.      * @throws SAXException 
  6.      * @throws IOException 
  7.      */  
  8.     public void parseNode(InputStream is) throws ParserConfigurationException, SAXException, IOException {  
  9.         DocumentBuilderFactory domfac = DocumentBuilderFactory.newInstance();  
  10.         DocumentBuilder domBuilder = domfac.newDocumentBuilder();  
  11.   
  12.   
  13.         // 默认是工程目录  
  14.     //  InputStream is = new FileInputStream("bin/resources/tinyioc.xml");  
  15.         Document doc = domBuilder.parse(is);  
  16.         Element root = doc.getDocumentElement();  
  17.         NodeList beans = root.getChildNodes();  
  18.         for (int i = 0; i < beans.getLength(); i++)   
  19.             if (beans.item(i) instanceof Element) {  
  20.                 Element el=(Element)beans.item(i);  
  21.                 parseElement(el);  
  22.             }  
  23.         is.close();  
  24.           
  25.     }  
  26.       
  27.     /** 
  28.      * 分析每一个bean的id class 
  29.      * @param el 
  30.      */  
  31.     public void parseElement(Element el){  
  32.         String id=el.getAttribute("id");  
  33.         String classPath=el.getAttribute("class");  
  34.     //  System.out.println(id+"  "+classPath);  
  35.         BeanDefinition bd=new BeanDefinition();  
  36.         bd.setBeanClassName(classPath);  
  37.         parseProperties(el,bd);  
  38.         beanDefinitionMap.put(id, bd);  
  39.     }  
  40.       
  41.     /** 
  42.      * 分析每一个bean的参数  并加入到beandefinition的property里面 
  43.      * @param el 
  44.      * @param bd 
  45.      */  
  46.     public void parseProperties(Element el,BeanDefinition bd){  
  47.         NodeList bl=el.getElementsByTagName("property");  
  48.         for (int i = 0; i < bl.getLength(); i++)   
  49.             if (bl.item(i) instanceof Element) {  
  50.                 Element property=(Element)bl.item(i);  
  51.                 String name=property.getAttribute("name");  
  52.             //  System.out.print("   "+name+"  ");  
  53.                 if (property.getAttribute("ref")!="") {  
  54.                     BeanReference br=new BeanReference(property.getAttribute("ref"));     
  55.                     PropertyValue pV=new PropertyValue(name,br);  
  56.                     bd.getPropertyValues().addPropertyValue(pV);  
  57.             //      System.out.println("   "+br.getName()+"  ");  
  58.                 }  
  59.                 if (property.getAttribute("value")!="") {  
  60.                     String value=property.getAttribute("value");  
  61.                     PropertyValue pV=new PropertyValue(name, value);  
  62.                     bd.getPropertyValues().addPropertyValue(pV);  
  63.                 //  System.out.println(value);  
  64.                 }  
  65.             }  
  66.           
  67.     }  
  68.   
  69.     public Map<String, BeanDefinition> getBeanDefinitionMap() {  
  70.         return beanDefinitionMap;  
  71.     }  


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


step6

如果仔细,比对XmlBeanDefinitionReader与AbstractBeanFactory,就能发现两个类里面都有beanDefinitionMap,重写两边,不合适。
另外在step5中
[java]  view plain  copy
  1. // 2.初始化BeanFactory并注册bean  
  2. BeanFactory beanFactory = new AbstractBeanFactory();  
  3. for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getBeanDefinitionMap().entrySet()) {  
  4.         ((AbstractBeanFactory)beanFactory).registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());  
  5. }  

按照使用者与创建者分离的原则,初始化注册的代码出现在客户端也不合适;
怎么办?
合起来呗。
还是先写测试代码 如下
[java]  view plain  copy
  1. <pre name="code" class="java">public void Step7() throws Exception {  
  2.         ApplicationContext ac=new ApplicationContext("bin/resources/tinyioc.xml");  
  3.         HelloWorldServiceImpl helloWorldService = (HelloWorldServiceImpl) ac.getBean("helloWorldService");  
  4.         helloWorldService.helloWorld3();  
  5.     }  
漂亮!关键就是ApplicationContext,上面已经说了,要把XmlBeanDefinitionReader与AbstractBeanFactory合起来,也就是说要把getBean与loadBeanDefinitions装到一个类里面去
[java]  view plain  copy
  1. package com.myspring.context;  
  2.   
  3. import java.util.Map;  
  4.   
  5. import com.bjsxt.spring.BeanFactory;  
  6. import com.myspring.beans.BeanDefinition;  
  7. import com.myspring.beans.factory.AbstractBeanFactory;  
  8. import com.myspring.beans.xml.XmlBeanDefinitionReader;  
  9.   
  10. public class ApplicationContext implements BeanFactory {  
  11.       
  12.     private AbstractBeanFactory abf=new AbstractBeanFactory();  
  13.   
  14.     public  ApplicationContext(String local) throws Exception {  
  15.     //  InputStream is = new FileInputStream(local);  
  16.         loadBeanDefinitions(abf,local);  
  17.     }  
  18.       
  19.     protected void loadBeanDefinitions(AbstractBeanFactory beanFactory,String configLocation) throws Exception {  
  20.         XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader();  
  21.         xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);  
  22.         for (Map.Entry<String, BeanDefinition> beanDefinitionEntry :   
  23.             xmlBeanDefinitionReader.getBeanDefinitionMap().entrySet()) {  
  24.             beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());  
  25.         }  
  26.     }  
  27.     @Override  
  28.     public Object getBean(String id) {  
  29.         // TODO Auto-generated method stub  
  30.         Object obj=null;  
  31.         try {  
  32.             obj = abf.getBean(id);  
  33.         } catch (Exception e) {  
  34.             // TODO Auto-generated catch block  
  35.             e.printStackTrace();  
  36.         }  
  37.         return obj;   
  38.     }  
  39. }  


AbstractBeanFactory与ApplicationContext都继承了BeanFactory,然后我们不直接用BeanFactory,而是让ApplicationContext中装一个AbstractBeanFactory,这不就是最简单的代理模式么?
代码到这里,就算是完成了黄亿华大神的TinySpring中IoC的大部分代码
之所以说是大部分,也就是说现在大家看到的代码还有一些部分与TinySpring不同
主要在这几个方面
1 Resources部分
  在我完成的代码里,读取xml的时候直接就是一个InputStream,TinySpring的方式是有一个Resource类,同时还有一个LoadResource类用来加载资源,当然实现的内部机理都是inputstream;
2 接口问题
  我一直认为,良好的代码是一次一次重构出来的,依我现在的水平,确实不能够很清晰地说出,分了那么多层接口,抽象类的实际作用,因此在我的代码里各个部分都很"薄弱"(只有一层)
3 对于类的加载,有两种方式一种直接加载,一种延迟加载,TinySpring最开始的那几个step还是在getBean的时候才newInstance的,但是到后面
[java]  view plain  copy
  1. protected void onRefresh() throws Exception{  
  2.      beanFactory.preInstantiateSingletons();  
  3.   }  
  4.   
  5.   
  6. public void preInstantiateSingletons() throws Exception {  
  7.     for (Iterator<String> it = this.beanDefinitionNames.iterator(); it.hasNext();) {  
  8.         String beanName = (String) it.next();  
  9.         getBean(beanName);  
  10.     }  
  11. }  
所以的类都直接加载了;


4 单例模式
TinySpring中一个bean默认只会加载一次,第二次getBean()的时候会取出之前已经creat的那个;
[java]  view plain  copy
  1. public Object getBean(String name) throws Exception {  
  2.         BeanDefinition beanDefinition = beanDefinitionMap.get(name);  
  3.         if (beanDefinition == null) {  
  4.             throw new IllegalArgumentException("No bean named " + name + " is defined");  
  5.         }  
  6.         Object bean = beanDefinition.getBean();  
  7.         if (bean == null) {                     //******************查找beanDefinition  
  8.             bean = doCreateBean(beanDefinition);  
  9.             bean = initializeBean(bean, name);  
  10.             beanDefinition.setBean(bean);  
  11.         }  
  12.         return bean;  
  13.     }  
  14.   
  15.   
  16.     protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {  
  17.         Object bean = createBeanInstance(beanDefinition);  
  18.         beanDefinition.setBean(bean);            //******************写入beanDefinition  
  19.         applyPropertyValues(bean, beanDefinition);  
  20.         return bean;  
  21.     }  



我写的代码中,没有上面的步骤,因此即使第二次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


Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐