Spring IOC和DI之间的关系

我们通过小故事来理解IOC和DI的关系

 

现实生活中,比如想吃水饺,在没有水饺店的日子里,最直观的做法就是:买面粉、蔬菜、肉等等食材,再去制造也就是去煮熟。这些都是主动创建的过程。也就是说想吃一顿水饺需要自己创造。

然而到了今时今日,水饺店出现,当我们想吃水饺时,只需要知道水饺点的联系方式,通过电话等渠道描述你的需求、地址、联系方式、下订单等待,过一会就有人送来水饺啦。

 

此时请注意你并没有 “主动” 创造水饺,而是由水饺店为你创造的,然而达到你的要求,甚至创造比你会更好一些。其实我们可以把水饺店理解为Spring框架中的控制反转。

IoC:Inverse of Control(控制反转)

读作“反转控制”,更好理解,不是什么技术,而是一种设计思想,就是将原本在程序中手动创建对象的控制权,交由Spring框架来管理。

简单说就是创建对象由以前的程序员自己new 构造方法来调用,变成了交由Spring创建对象 

让我们用代码来说明:

一、pom文件

  <properties>  
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
        <springversion>4.0.0.RELEASE</springversion>  
        <junitversion>4.9</junitversion>  
  </properties> 
  <dependencies>
    <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junitversion}</version>
            <scope>test</scope>
        </dependency>
    
        <!-- spring核心包 -->  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-core</artifactId>  
            <version>${springversion}</version>  
        </dependency>
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-web</artifactId>  
            <version>${springversion}</version>  
        </dependency>  
        
  </dependencies>

二、创建饺子类

public class Dumplings {

	private String pie; // 什么馅
	
	private String size; // 大小份
    
    // 省略setget方法
}

三、创建 applicationContext.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="dumplings" class="com.pojo.Dumplings">
        <property name="pie" value="芹菜猪肉馅水饺"/>
        <property name="size" value="超大份"/>
    </bean>

</beans>

四、测试类

    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext(
                new String[]{"applicationContext.xml"}
        );

        Dumplings dumplings = (Dumplings) context.getBean("dumplings");
        System.out.println(dumplings.getPie());
        System.out.println(dumplings.getSize());
    }

五、测试结果

芹菜猪肉馅水饺
超大份

通过以上的实现我们可以总结出以下2点。

传统方式:

通过new 关键字主动创建一个对象。

IOC方式:

对象的生命周期由Spring来管理。直接从Spring获取一个对象。就像控制权自己手里交给了Spring。

 

DI:Dependency Injection(依赖注入)

指 Spring 创建对象的过程中,将对象依赖属性(简单值,集合,对象)通过配置设值给该对象

继续上面的例子

新增饭店的类

public class Hotel {
	// 饺子类
	private Dumplings dumplings;
	// 果汁类
	private Juice juice;
    
    // 省略setter方法
	
	// 生成订单
	public String getOrderInfo() {
		return "小明点了:"+dumplings.getSize()+","+dumplings.getPie()+"和"+juice.getName();
	}
}

新增果汁类

public class Juice {
	// 果汁名称
	private String name;
    // 省略setget方法
}

修改 applicationContext.xml 文件内容

  • 注意:这里要使用 ref 来注入另一个对象
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="dumplings" class="com.pojo.Dumplings">
        <property name="pie" value="芹菜猪肉馅水饺"/>
        <property name="size" value="超大份"/>
    </bean>
    <bean name="juice" class="com.pojo.Juice">
        <property name="name" value="苹果汁"/>
    </bean>
    
    <bean name="hotel" class="com.pojo.Hotel">
        <property name="dumplings" ref="dumplings"/>
        <property name="juice" ref="juice"/>
    </bean>
    
</beans>

测试方法

    @Test
    public void saveOrderTest(){
    	ApplicationContext context = new ClassPathXmlApplicationContext(
    			new String[]{"applicationContext.xml"}
    			);
    	
    	Hotel hotel = (Hotel) context.getBean("hotel");
    	System.out.println(hotel.getOrderInfo());
    }

测试结果

小明点了:超大份,芹菜猪肉馅水饺和苹果汁

总结:  依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。

借鉴于 Martin Fowler 2004年写的<Inversion of Control Containers and the Dependency Injection pattern>

文章地址      http://martinfowler.com/articles/injection.html

2004年,Martin Fowler 探讨了同一个问题,既然IOC是控制反转,那么到底是“哪些方面的控制被反转了呢?”,经过详细地分析和论证后,他得出了答案:“获得依赖对象的过程被反转了”。控制被反转之后,获得依赖对象的过程由自身管理变为了由IOC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection)”。他的这个答案,实际上给出了实现IOC的方法:注入。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。

聊聊使用IOC需要注意的要点

软件系统中由于引入了第三方IOC容器,生成对象的步骤变得有些复杂,本来是两者之间的事情,又凭空多出一道手续,所以,我们在刚开始使用IOC框架的时候,会感觉系统变得不太直观。所以,引入了一个全新的框架,就会增加团队成员学习和认识的培训成本,并且在以后的运行维护中,还得让新加入者具备同样的知识体系。

由于IOC容器生成对象是通过反射方式,在运行效率上有一定的损耗。如果你要追求运行效率的话,就必须对此进行权衡。

具体到IOC框架产品(比如:Spring)来讲,需要进行大量的配制工作,比较繁琐,对于一些小的项目而言,客观上也可能加大一些工作成本。

IOC框架产品本身的成熟度需要进行评估,如果引入一个不成熟的IOC框架产品,那么会影响到整个项目,所以这也是一个隐性的风险。

我们大体可以得出这样的结论:一些工作量不大的项目或者产品,不太适合使用IOC框架产品。另外,如果团队成员的知识能力欠缺,对于IOC框架产品缺乏深入的理解,也不要贸然引入。最后,特别强调运行效率的项目或者产品,也不太适合引入IOC框架产品,像WEB2.0网站就是这种情况。

聊聊IOC的优缺点

IOC的优点

实现组件之间的解耦,提高程序的灵活性和可维护性。

IOC的缺点

创建对象的步骤变复杂了,不直观,当然这是对不习惯这种方式的人来说的。

因为使用反射来创建对象,所以在效率上会有些损耗。但相对于程序的灵活性和可维护性来说,这点损耗是微不足道的。

缺少IDE重构的支持,如果修改了类名,还需到XML文件中手动修改,这似乎是所有XML方式的缺憾所在。

总结

这么看的话其实IoC就是一个工厂模式的升级版!当然要做一个成熟的IoC框架,还是非常多细致的工作要做,Spring不仅提供了一个已经成为业界标准的Java IoC框架,还提供了更多强大的功能。

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值