Spring IOC 解读1

IoC(控制反转:Inverse of Control)是Spring容器的内核.

其实这个Spring架构核心的概念没有这么复杂,更不像有些书上描述的那样晦涩。java程序员都知道:java程序中的每个业务逻辑至少需要两个或以上的对象来协作完成,通常,每个对象在使用他的合作对象时,自己均要使用像new object() 这样的语法来完成合作对象的申请工作。你会发现:对象间的耦合度高了。

IOC的思想是:Spring容器来实现这些相互依赖对象的创建、协调工作。对象只需要关系业务逻辑本身就可以了。从这方面来说,对象如何得到他的协作对象的责任被反转了(IOC、DI)。

一个比较好的例子:

那么IoC是如何做的呢?有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男男女女的资料,我可以向婚介提出一个列表,告诉它我想找个什么样的女朋友,比如长得像李嘉欣,身材像林熙雷,唱歌像周杰伦,速度像卡洛斯,技术像齐达内之类的,然后婚介就会按照我们的要求,提供一个mm,我们只需要去和她谈恋爱、结婚就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的机构来控制。Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。如果你还不明白的话,我决定放弃。

思路
  1. 启动容器时,加载xml文件
  2. 读取xml文件内的bean信息,并使用反射技术将bean实例化,并装入容器
  3. 确认bean之间的以来关系,进行注入。
实现

首先从例子入手,看下IOC内部的实现机理。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" 
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <!--这是吃橘子的Bean -->
  <bean id="eatOrange" class="it.spring.liao.com.EatOrange"></bean>
    <!--这是吃苹果的Bean -->
  <bean id="eatApple" class="it.spring.liao.com.EatApple"></bean>
  <bean id="person" class="it.spring.liao.com.Person">
    <!-- 这里我们注入的是吃橘子的bean-->
    <property name="eat" ref="eatOrange"/>
  </bean>
</beans>

// 下面是关键代码
package it.spring.liao.com;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class BeanFactory {

  // 用于存放bean实例的集合
  private Map<String, Object> beanMap = new HashMap<String, Object>();

  /**
   * bean工厂的初始化. <br>
   * 
   * @param xml
   *      配置文件路径
   */
  public void init(String xml) {
    try {
      // 1.创建读取配置文件的reader对象
      SAXReader reader = new SAXReader();
      // 2.获取当前线程中的类装载器对象
      ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
      // 3.从class目录下获取指定的xml文件
      InputStream ins = classLoader.getResourceAsStream(xml);
      // 4.使用dom4j 解析xml文件
      Document doc = reader.read(ins);
      Element root = doc.getRootElement();
      // 5.初始化bean
      setBean(root);
      // 6.注入bean的依赖关系
      setPv(root);
    } catch (Exception e) {
      System.out.println(e.toString());
    }
  }

  /**
   * 初始化bean
   * 
   * @param root
   *      xml文件
   * @throws Exception
   */
  public void setBean(Element root) throws Exception {
    // 1.遍历xml文件当中的Bean实例
    for (Iterator i = root.elementIterator("bean"); i.hasNext();) {
      Element foo = (Element) i.next();
      // 2.针对每个Bean实例,获取bean的属性id和class
      String id = foo.attribute("id").getText();
      String cls = foo.attribute("class").getText();
      // 3.利用Java反射机制,通过class的名称获取Class对象
      Class bean = Class.forName(cls);
      // 4.创建对象
      Object obj = bean.newInstance();
      // 5.将对象放入beanMap中,其中key为bean的id值,value为bean的实例
      beanMap.put(id, obj);
    }
  }

  /**
   * 注入bean的依赖关系
   * 
   * @param root
   *      xml文件
   * @throws Exception
   */
  public void setPv(Element root) throws Exception {
    for (Iterator it = root.elementIterator("bean"); it.hasNext();) {
      Element foo = (Element) it.next();

      // 1.针对每个Bean实例,获取bean的属性id和class
      String cls = foo.attribute("class").getText();
      String id = foo.attribute("id").getText();

      // 2.利用Java反射机制,通过class的名称获取Class对象
      Class bean1 = Class.forName(cls);

      // 3.获取对应class的信息
      java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean1);

      // 4.获取其属性描述
      java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors();

      // 5遍历该bean的property属性
      for (Iterator ite = foo.elementIterator("property"); ite.hasNext();) {
        Element foo2 = (Element) ite.next();

        // 6.获取该property的name属性
        String name = foo2.attribute("name").getText();
        String ref = foo2.attribute("ref").getText();

        // 7.在类中寻找与xml配置文件中该bean的property属性名相同的属性
        for (int k = 0; k < pd.length; k++) {
          // 8.如果相等,证明已经找到对应得属性
          if (pd[k].getName().equalsIgnoreCase(name)) {
            Method mSet = null;
            // 9.利用反射,获取该属性的set方法
            mSet = pd[k].getWriteMethod();
            // 10.用原beanMap中该bean的实例,执行该属性的set方法,并从原beanMap中获取该属性的依赖值
            mSet.invoke(beanMap.get(id), beanMap.get(ref));
          }
        }
        break;
      }
    }
  }

  /**
   * 通过bean的id获取bean的实例
   * 
   * @param beanName
   *      bean的id
   * @return 返回对应对象
   */
  public Object getBean(String beanName) {
    Object obj = beanMap.get(beanName);
    return obj;
  }

}




  /**
   * 测试方法.
   * 
   * @param args
   */
  public static void main(String[] args) {
    //使用我们自己写的 BeanFactory
    BeanFactory factory = new BeanFactory();
    factory.init("eat.xml");
    Person javaBean = (Person) factory.getBean("person");
    System.out.println(javaBean.eat()); 
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值