预备知识: Java反射原理,XML及其解析
 
IOC:Inversion of Control,控制反转,它最主要反映的是与传统面向对象(OO)编程的不同。通常我们编程实现某种功能都需要几个对象相互作用,从编程的角度出发,也就是一个主对象要保存其他类型对象的引用,通过调用这些引用的方法来完成任务。如何获得其他类型的对象引用呢?一种方式是主对象内部主动获得所需引用;另一种方式是在主对象中设置setter 方法,通过调用setter方法或构造方法传入所需引用。后一种方式就叫IOC,也是我们常常所说的依赖注入。以下我们用一个简单的例子来说明传统OO编程与IOC编程的差别。
   这个例子的目的是根据时间不同返回不同的问候字符串, 比如Good Morning, world或Good afternoon, World。
服务接口:
    package com.kettas.springdev.ioc;
public interface HelloIF {
     String sayHello();
}
 
传统实现:
   package com.kettas.springdev.ioc;
   import java.util.Calendar;
public class HelloIFImpl implements HelloIF{
      private Calendar cal;    //我们需要的引用
 
        public HelloIFImpl(){
                     cal = Calendar.getInstance();   //主动获取
}
 
public String sayHello(){
    if(cal.get(Calendar.AM_PM) == Calendar.AM) return “Good morning, World”;
    else return “Good afternoon, World”;
}
}
 
采用IOC方式:
package com.kettas.springdev.ioc;
   import java.util.Calendar;
public class HelloIFImpl implements HelloIF{
      private Calendar cal;   //我们需要的引用
 
public void setCal(Calendar cal){ this.cal = cal;} //依赖注入
  
public String sayHello(){
    if(cal.get(Calendar.AM_PM) == Calendar.AM) return “Good morning, World”;
    else return “Good afternoon, World”;
}
}
 
在这里你也许会问:我看不出有太大差别,并且依赖注入还需要我先创建外部的Calendar对象,然后再传到HelloIFImpl对象中。
 
是的,如果我们直接创建HelloIFImpl对象没有任何的优势。如果我们让一个Bean工厂来帮我们创建HelloIF类型的引用就有优势了,当然要在这样的前提下: 1. Bean工厂可以随时改变HelloIF实现的类型;2. Bean工厂在创建好对象后主动调用依赖注入的方法。所以离开Bean工厂谈IOC是没有什么意义的, 开源框架Spring就提供了灵活多样的Bean工厂。以上例子可以通过如下XML片段来告诉Bean工厂如何创建对象并注入依赖:
<beans>
   <bean id=”hello” class=”com.kettas.springdev.ioc.HelloIFImpl”> <!—调用构造方法产生对象à
      <property name=”cal” > <!—注入下面定义的Calendar引用-->
          <ref local=”calendar”/>
</property>
   </bean>
 
   <bean id=”calendar” class=”java.util.GregorianCalendar” /> <!—产生calendar对象à 
</beans>
 
Bean工厂通过解析以上的配置就知道如何创建对象,如何注入依赖。
 
那Bean工厂到底如何实现所说的功能呢?从以上的XML配置片段我们可以看出
 
有两种数据类型:一个是Bean的定义(BeanDefinition);一个是对Bean的属性(Property)的定义(PropertyDefinition),嵌套在Bean定义中。Bean的定义包括:id, 类名(clazz)和一到多个PropertyDefinition; Property的定义包括: name, refName(如果是引用,指向另一个Bean), value(如果是基本数据类型), ifRef(是否是引用)。Java通过反射机制可以调用构造方法创建对象,也可以调用该实例上的方法。Bean工厂通过递归调用创建配置文件里定义的Bean对象,并调用这些对象的setter方法来实现依赖注入。而依赖注入都使用的是Bean的id, 所以我们在Bean工厂里用一个Map来保存Bean的定义,该Map的key是Bean的id。创建的Bean对象都是单例的,所以我们要保存Bean对象;而客户是通过id来获取Bean对象,所以我们也用Map来缓存。以下的代码提供了上述问题的解决方案(当然这是最简单的一种:只调用没有参数的构造方法,只实现基于setter的依赖注入,注入的依赖只能是基本数据类型或引用, xml解析没有做合法性检测等)
 
Bean的定义:BeanDefinition,java:
 
package com.kettas.springdev.ioc.bf;
 
import java.util.HashSet;
import java.util.Set;
 
public class BeanDefinition { //对应<bean>元素
       private String clazz;     //Bean类名全路径, 对应<bean>的attribute: class
       private String id;        //唯一属性, 对应<bean>的attribute: id
       private Set<PropertyDefinition> propertyDefinitions     //依赖描述, 对应<property>元素
        = new HashSet<PropertyDefinition>();
      
       public String getId() {
              return id;
       }
       public void setId(String id) {
              this.id = id;
       }
       public String getClazz() {
              return clazz;
       }
       public void setClazz(String clazz) {
              this.clazz = clazz;
       }
       public Set<PropertyDefinition> getPropertyDefinitions() {
              return propertyDefinitions;
       }
       public void setPropertyDefinitions(Set<PropertyDefinition> propertyDefinitions) {
              this.propertyDefinitions = propertyDefinitions;
       }
      
       public void addPropertyDefinition(PropertyDefinition pd){
              this.propertyDefinitions.add(pd);
       }
}
 
Bean的属性的定义:PropertyDefinition.java:
 
package com.kettas.springdev.ioc.bf;
 
public class PropertyDefinition { //对应<property>元素
       private String name;         // <property> attribute: name
       private String refName;      // <property>子元素<ref>的attribute(如local, bean等)的值
       private String value;   //<property>子元素<value>的字符串子元素
       private boolean isRef;        //是否为引用
      
       public boolean isRef() {
              return isRef;
       }
       public void setRef(boolean isRef) {
              this.isRef = isRef;
       }
       public String getName() {
              return name;
       }
       public void setName(String name) {
              this.name = name;
       }
       public String getRefName() {
              return refName;
       }
       public void setRefName(String refName) {
              this.refName = refName;
       }
       public String getValue() {
              return value;
       }
       public void setValue(String value) {
              this.value = value;
       }
      
      
}
 
Bean工厂接口: BeanFactory.java:
package com.kettas.springdev.ioc.bf;
 
public interface BeanFactory {
       Object getBean(String id);
}
 
BeanFactory的一个实现:XmlBeanFactory.java:
 
package com.kettas.springdev.ioc.bf;
 
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
 
public class XmlBeanFactory implements BeanFactory{
       private Map<String, Object> beans
        = new HashMap<String, Object>(); //Bean对象缓存
       private Set<BeanDefinition> beanDefinitions
         = new HashSet<BeanDefinition>(); //Bean的定义
      
       public XmlBeanFactory(String xmlFileClassPath){
              new BeanFactoryConfiguration(beanDefinitions, xmlFileClassPath);
       }
      
       public Object getBean(String id){
              if(beans.containsKey(id)) return beans.get(id);
              Object bean = null;
              BeanDefinition bd = getBeanDefintion(id);
              try{
                     Class beanClass = Class.forName(bd.getClazz());
                     bean = beanClass.newInstance();
                     for(PropertyDefinition pd : bd.getPropertyDefinitions()){
                            String property = pd.getName();
                            Method m = getSetter(beanClass,property);
                            //System.out.println(property + " : " + pd.isRef());
                            if(pd.isRef()){
                                   m.invoke(bean, getBean(pd.getRefName()));
                            }else{
                                   setValue(m, bean, pd.getValue());
                            }
                     }
                     beans.put(id, bean);
              }catch(Exception e){
                     throw new RuntimeException("Can't create bean " + id, e);
              }
             
              return bean;
       }
      
       private void setValue(Method m, Object bean, String value) throws Exception {
              // TODO Auto-generated method stub
              Class paramType = m.getParameterTypes()[0];
              //System.out.println(paramType.getName());
              if(paramType == byte.class || paramType == Byte.class){
                     Byte b = new Byte(value);
                     m.invoke(bean, b);
              }else if(paramType == short.class || paramType == Short.class){
                     Short s = new Short(value);
                     m.invoke(bean, s);
              }else if(paramType == char.class || paramType == Character.class){
                     Character c = new Character(value.charAt(0));
                     m.invoke(bean, c);
              }else if(paramType == int.class || paramType == Integer.class){
                     Integer i = new Integer(value);
                     m.invoke(bean, i);
              }else if(paramType == float.class || paramType == Float.class){
                     Float f = new Float(value);
                     m.invoke(bean, f);
              }else if(paramType == double.class || paramType == Double.class){
                     Double d = new Double(value);
                     m.invoke(bean, d);
              }else{
                     m.invoke(bean, value);
              }
       }
 
       private Method getSetter(Class beanClass, String property) throws Exception {
              // TODO Auto-generated method stub
              StringBuilder sb = new StringBuilder("set");
              char c = property.charAt(0);
              if(c >= 'a' && c <= 'z') c -= 32;
              sb.append(c).append(property.substring(1));
              Method[] methods = beanClass.getMethods();
              for(Method m : methods){
                     if(m.getName().equals(sb.toString()))
                            return m;
              }
             
              throw new RuntimeException("No such property: " + property);
       }
 
       private BeanDefinition getBeanDefintion(String id){
              for(BeanDefinition bd : beanDefinitions){
                     if(bd.getId().equals(id))
                            return bd;
              }
             
              throw new RuntimeException("There is not [id="
                            + id + "] in the xml configuration file");
       }
}
 
 
解析Xml文件,生成BeanDefintion和PropertyDefinition: BeanFactoryConfiguration.java
package com.kettas.springdev.ioc.bf;
 
import java.util.Set;
 
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
 
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
 
public class BeanFactoryConfiguration {
 
       public BeanFactoryConfiguration(Set<BeanDefinition> beanDefinitions, String xmlFileClassPath) {
              // TODO Auto-generated constructor stub
              DocumentBuilderFactory dbf =
                     DocumentBuilderFactory.newInstance();
              try {
                     DocumentBuilder db = dbf.newDocumentBuilder();
                     Document doc = db.parse(
                            this.getClass().getResourceAsStream(xmlFileClassPath)    
                     );
                     parse(doc, beanDefinitions);
              } catch (Exception e) {
                     // TODO Auto-generated catch block
                     throw new RuntimeException("can't parse the configuration file : " + xmlFileClassPath, e);
              }
       }
 
       private void parse(Document doc, Set<BeanDefinition> beanDefinitions) {
              // TODO Auto-generated method stub
              NodeList beans = doc.getElementsByTagName("bean");
              int len = beans.getLength();
              for(int i = 0; i < len; i++){
                     BeanDefinition bd = new BeanDefinition();
                     Element n = (Element)beans.item(i);
                     NamedNodeMap nnm = n.getAttributes();
                     for(int j = 0; j < nnm.getLength(); j++){
                            Node attr = nnm.item(j);
                            //System.out.println(attr.getNodeName() + " " + attr.getNodeValue());
                            if(attr.getNodeName().equals("id"))
                                   bd.setId(attr.getNodeValue());
                            else
                                   bd.setClazz(attr.getNodeValue());
                     }
                    
                     NodeList pros = n.getElementsByTagName("property");
                     for(int j = 0; j < pros.getLength(); j++){
                            bd.addPropertyDefinition(createPropertyDefinition(pros.item(j)));
                     }
                    
                     beanDefinitions.add(bd);
              }
       }
 
       private PropertyDefinition createPropertyDefinition(Node node) {
              // TODO Auto-generated method stub
              PropertyDefinition pd = new PropertyDefinition();
              NamedNodeMap nnm = node.getAttributes();
              pd.setName(nnm.item(0).getNodeValue());
              NodeList nl = ((Element)node).getElementsByTagName("value");
              if(nl != null && nl.getLength() > 0){
                     pd.setValue(nl.item(0).getFirstChild().getNodeValue());
              }else{
                     pd.setRef(true);
                     nl = ((Element)node).getElementsByTagName("ref");
                     Node ref = nl.item(0);
                     pd.setRefName(ref.getAttributes().item(0).getNodeValue());
              }
      
              return pd;
       }
 
}
 
 
测试程序:
 
package com.kettas.springdev.ioc.bf;
 
import springdev.ioc.day1.HelloIF;
 
public class TestMyBeanFactory {
 
       /**
        * @param args
        */
       public static void main(String[] args) {
              // TODO Auto-generated method stub
              BeanFactory bf = new XmlBeanFactory(
                            "/com/kettas/springdev/ioc/beans.xml"
              );
             
              HelloIF hello = (HelloIF)bf.getBean("hello");
              System.out.println(hello.sayHello());
       }
 
}

IOC介绍及其简单实现的更多相关文章

  1. 【java基础】IOC介绍及其简单实现

    控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心. 控制反转一般分为两种类型,依赖注入 ...

  2. 基于.NET CORE微服务框架 -surging的介绍和简单示例 (开源)

    一.前言 至今为止编程开发已经11个年头,从 VB6.0,ASP时代到ASP.NET再到MVC, 从中见证了.NET技术发展,从无畏无知的懵懂少年,到现在的中年大叔,从中的酸甜苦辣也只有本人自知.随着 ...

  3. Spring升级案例之IOC介绍和依赖注入

    Spring升级案例之IOC介绍和依赖注入 一.IOC的概念和作用 1.什么是IOC 控制反转(Inversion of Control, IoC)是一种设计思想,在Java中就是将设计好的对象交给容 ...

  4. 【转载】Ssh整合开发介绍和简单的登入案例实现

    Ssh整合开发介绍和简单的登入案例实现 Ssh整合开发介绍和简单的登入案例实现 一  介绍: Ssh是strtus2-2.3.1.2+ spring-2.5.6+hibernate-3.6.8整合的开 ...

  5. python模块介绍- HTMLParser 简单的HTML和XHTML解析器

    python模块介绍- HTMLParser 简单的HTML和XHTML解析器 2013-09-11 磁针石 #承接软件自动化实施与培训等gtalk:ouyangchongwu#gmail.comqq ...

  6. WebRTC介绍及简单应用

    WebRTC介绍及简单应用 WebRTC,即Web Real-Time Communication,web实时通信技术.简单地说就是在web浏览器里面引入实时通信,包括音视频通话等. WebRTC实时 ...

  7. 1. pyhanlp介绍和简单应用

    1. pyhanlp介绍和简单应用 2. 观点提取和聚类代码详解 1. 前言 中文分词≠自然语言处理! 中文分词只是第一步:HanLP从中文分词开始,覆盖词性标注.命名实体识别.句法分析.文本分类等常 ...

  8. C#串口介绍以及简单串口通信程序设计实现

    C#串口介绍以及简单串口通信程序设计实现 周末,没事干,写个简单的串口通信工具,也算是本周末曾来过,废话不多,直接到主题 串口介绍 串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口) ...

  9. 消息队列介绍、RabbitMQ&Redis的重点介绍与简单应用

    消息队列介绍.RabbitMQ&Redis的重点介绍与简单应用 消息队列介绍.RabbitMQ.Redis 一.什么是消息队列 这个概念我们百度Google能查到一大堆文章,所以我就通俗的讲下 ...

随机推荐

  1. Linux定时器的使用(三种方法)

    使用定时器的目的无非是为了周期性的执行某一任务,或者是到了一个指定时间去执行某一个任务.要达到这一目的,一般有两个常见的比较有效的方法.一个是用linux内部的三个定时器,另一个是用sleep, us ...

  2. 前端js常用正则表达式实例讲解

    本文内容整理自他人优秀的博客,非纯原创.仅借此学习和整理. 1.匹配用户名 规则描述: 长度4-6位: {4,16} 字母: [a-z] [A-Z] 数字: [0-9] 下划线: [_] 减号: [- ...

  3. POJ 3624 Charm Bracelet 0-1背包

    传送门:http://poj.org/problem?id=3624 题目大意:XXX去珠宝店,她需要N件首饰,能带的首饰总重量不超过M,要求不超过M的情况下,使首饰的魔力值(D)最大. 0-1背包入 ...

  4. C++中使用soap toolkit访问webService详解

    使用Visual C++开发SOAP客户端应用  使用Visual C++开发SOAP客户端应用 简介 在本篇文章中,我们将讨论如何使用Visual C++开发一个简单的SOAP客户端应用程序,我们还 ...

  5. MySql的事务操作与演示样例

    事务就是一个逻辑工作单元的一系列步骤. 事务是用来保证数据操作的安全性 事务的特征: Atomicity(原子性) Consistency(稳定性,一致性) Isolation(隔离性) Durabi ...

  6. keil编译后Program Size: Code=46284 RO-data=988 RW-data=580 ZI-data=1094588

    Program Size: Code=46284 RO-data=988 RW-data=580 ZI-data=1094588 Code      :   程序中代码所占字节大小 RO-data : ...

  7. ds finder 唤醒

    http://www.hangge.com/blog/cache/detail_594.html

  8. HTTP请求头与响应头

    http://m.blog.csdn.net/article/details?id=48918857 本篇文章中,将学习一下HTTP请求头与响应头的知识. 一.HTTP头引入: 正确的设置HTTP头部 ...

  9. 一起talk C栗子吧(第八十三回:C语言实例--进程间通信概述)

    各位看官们,大家好,前二回中咱们说的是进程停止的样例,这一回咱们说的样例是:进程间通信.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们.每一个进程都拥有自己的资源,假设不同进程之间须要共享 ...

  10. swift学习第七天:字典

    字典的介绍 字典允许按照某个键来访问元素 字典是由两部分集合构成的,一个是键(key)集合,一个是值(value)集合 键集合是不能有重复元素的,而值集合是可以重复的,键和值是成对出现的 Swift中 ...