依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(多是一个Java实例,调用者)须要另外一个角色(另外一个Java实例,被调用者)的协助时,在 传统的程序设计过程当中,一般由调用者来建立被调用者的实例。但在Spring里,建立被调用者的工做再也不由调用者来完成,所以称为控制反转;建立被调用者 实例的工做一般由Spring容器来完成,而后注入调用者,所以也称为依赖注入。java
总结
(1)也许有人说,IoC和工厂模式不是同样的做用吗,用IoC好象还麻烦一点。
举个例子,若是用户需求发生变化,要把Chinese类修改一下。那么前一种工厂模式,就要更改Factory类的方法,而且从新编译布署。而IoC只需 要将class属性改变一下,而且因为IoC利用了Java反射机制,这些对象是动态生成的,这时咱们就能够热插拨Chinese对象(没必要把原程序中止 下来从新编译布署,java特性 须要从新编译)
(2)也许有人说,即然IoC这么好,那么我把系统全部对象都用IoC方式来生成。
注意,IoC的灵活性是有代价的:设置步骤麻烦、生成对象的方式不直观、反射比正常生成对象在效率上慢一点。所以使用IoC要看有没有必要,我认为比较通用的判断方式是:用到工厂模式的地方均可以考虑用IoC模式。
(3)在上面的IoC的方式里,还有一些能够变化的地方。好比,bean.xml不必定要放在项目录下,也能够放在其余地方,好比cn.com.chengang.spring包里。不过在使用时也要变化一下,以下所示:
new FileSystemXmlApplicationContext("src/cn/com/chengang/spring/bean.xml");
另外,bean.xml也能够改为其余名字。这样咱们在系统中就能够分门别类的设置不一样的bean.xml。
(4)关于IoC的低侵入性。
什么是低侵入性?若是你用过Struts或EJB就会发现,要继承一些接口或类,才能利用它们的框架开发。这样,系统就被绑定在Struts、EJB上 了,对系统的可移植性产生不利的影响。若是代码中不多涉及某一个框架的代码,那么这个框架就能够称作是一个低侵入性的框架。
Spring的侵入性很低,Humen.java、Chinese.java等几个类都没必要继承什么接口或类。但在ClientTest里仍是有一些 Spring的影子:FileSystemXmlApplicationContext类和ctx.getBean方式等。
如今,低侵入性彷佛也成了断定一个框架的实现技术好坏的标准之一。spring
一、以下图所示有三个类,Human(人类)是接口,Chinese(中国人)是一个子类,American(美国人)是另一个子类。 源代码以下: java 代码package cn.com.chengang.spring; public interface Human { void eat(); void walk(); } package cn.com.chengang.spring; public class Chinese implements Human { /* (非 Javadoc) * @see cn.com.chengang.spring.Human#eat() */ public void eat() { System.out.println("中国人对吃颇有一套"); } /* (非 Javadoc) * @see cn.com.chengang.spring.Human#walk() */ public void walk() { System.out.println("中国人行如飞"); } } package cn.com.chengang.spring; public class American implements Human { /* (非 Javadoc) * @see cn.com.chengang.spring.Human#eat() */ public void eat() { System.out.println("美国人主要以面包为主"); } /* (非 Javadoc) * @see cn.com.chengang.spring.Human#walk() */ public void walk() { System.out.println("美国人以车代步,有四肢退化的趋势"); } } 二、对以上对象采用工厂模式的用法以下 建立一个工厂类Factory,以下。这个工厂类里定义了两个字符串常量,所标识不一样的人种。getHuman方法根据传入参数的字串,来判断要生成什么样的人种。 java 代码package cn.com.chengang.spring; public class Factory { public final static String CHINESE = "Chinese"; public final static String AMERICAN = "American"; public Human getHuman(String ethnic) { if (ethnic.equals(CHINESE)) return new Chinese(); else if (ethnic.equals(AMERICAN)) return new American(); else throw new IllegalArgumentException("参数(人种)错误"); } } 下面是一个测试的程序,使用工厂方法来获得了不一样的“人种对象”,并执行相应的方法。 java 代码package cn.com.chengang.spring; public class ClientTest { public static void main(String[] args) { Human human = null; human = new Factory().getHuman(Factory.CHINESE); human.eat(); human.walk(); human = new Factory().getHuman(Factory.AMERICAN); human.eat(); human.walk(); } } 三、采用Spring的IoC的用法以下: 在项目根目录下建立一个bean.xml文件 xml 代码<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="Chinese" class="cn.com.chengang.spring.Chinese"/> <bean id="American" class="cn.com.chengang.spring.American"/> </beans> 修改ClientTest程序以下: java 代码package cn.com.chengang.spring; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class ClientTest { public final static String CHINESE = "Chinese"; public final static String AMERICAN = "American"; public static void main(String[] args) { // Human human = null; // human = new Factory().getHuman(Factory.CHINESE); // human.eat(); // human.walk(); // human = new Factory().getHuman(Factory.AMERICAN); // human.eat(); // human.walk(); ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml"); Human human = null; human = (Human) ctx.getBean(CHINESE); human.eat(); human.walk(); human = (Human) ctx.getBean(AMERICAN); human.eat(); human.walk(); } }
从这个程序能够看到,ctx就至关于原来的Factory工厂,原来的Factory就能够删除掉了。而后又把Factory里的两个常量移到了ClientTest类里,整个程序结构基本同样。
再回头看原来的bean.xml文件的这一句:
<bean id="Chinese" class="cn.com.chengang.spring.Chinese"/>
id就是ctx.getBean的参数值,一个字符串。class就是一个类(包名+类名)。而后在ClientTest类里得到Chinese对象就是这么一句
human = (Human) ctx.getBean(CHINESE);
由于getBean方法返回的是Object类型,因此前面要加一个类型转换框架