Spring-IoC概念

IoC概述

  IoC(Inverse of Controller,控制反转)是spring容器的基础,AOP以及声明式事务等功能都以此为基础。对于刚开始接触Spring的程序员来说,IoC这个重要的概念比较晦涩难懂,在此通过一个例子说明这个概念。

1. 通过实例理解IoC概念

  以《墨攻》电影为例,其中有一个场景,当刘德华所饰演的墨者革离到达梁国都城下时,城上梁国守军问道:“来者何人?”刘德华回答:“墨者革离!”我们不妨通过Java语言为这个“城门叩问”的场景编写剧本,并借此理解IoC的概念,代码如下所示。

/**
 * 通过使用演员编排剧本
 */ 
public class MoAttack {
    public void cityGateAsk() {
        // 演员直接侵入剧本
        LiuDeHua ldh = new LiuDeHua();
        ldh.responseAsk("墨者革离!");
    }
}

  通过代码我们会发现作为具体角色饰演者的刘德华直接侵入剧本,使剧本和演员直接耦合在一起。一个明智的编剧在剧情创作时应围绕故事的角色进行,而不应考虑角色的具体饰演者,这样才能在剧本投拍时自由的选择任何合适的演员,而非绑定在某一个人身上。通过以上分析,我们需要为该剧本的主人公革离定义一个接口,接口如下所示。

/**
 * 通过使用角色编排剧本
 */ 
public class MoAttack {
    public void cityGateAsk() {
        // 引入革离角色接口
        GeLi geli = new LiuDeHua();
        // 通过接口展开剧情
        geli.responseAsk("墨者革离!");
    }
}

  增加GeLi角色后,该剧本的情节通过角色展开,在拍摄时角色由演员饰演。但是MoAttack却同时依赖于GeLi接口和LiuDeHua类,并没有达到我们所期盼的剧本仅依赖于角色的目的。如何让LiuDeHua和剧本无关而又完成GeLi的具体动作呢?我们可以通过导演负责剧本,角色,饰演者三者的协调。通过引入导演,使得剧本和具体饰演者解耦。
  现在,让我们看看IoC的概念,IoC的字面意思是控制反转,概念包含两方面:
    1. 控制:选择GeLi角色扮演者的控制权
    2. 反转:控制权从《墨攻》剧本中移除,转交给导演的手中
  对于软件而言,某一接口具体实现类的选择控制权从调用类中移除,转交给第三方决定,即由Spring容器借由Bean配置进行控制。因为IoC确实不够开门见山,因此业界曾进行广泛的讨论,最终软件界的泰斗级任务Martin Fowler提出了DI(Dependency Injection,依赖注入)概念用来代替IoC,即让调用类对某一接口实现类的依赖关系由第三方注入,以移除调用类对某一接口实现类的依赖。

2. IoC类型

  从注入方法上来看,IoC主要可以划分为三种类型:构造函数注入,属性注入和接口注入。Spring支持构造注入以及属性注入。下面继续使用以上的例子说明三种注入方式的区别。

2.1 构造函数注入

  通过调用类的构造函数,将接口实现类通过构造函数变量传入,代码如下所示。

public class MoAttack {
    private GeLi geli;

    // 注入革离具体饰演者
    public MoAttack(GeLi geli) {
        this.geli = geli;
    }

    public void cityGateAsk() {
        geli.responseAsk("墨者革离!");
    }
}

  MoAttack的构造函数不关心具体由谁来饰演革离这个角色,只要传入的饰演者按剧本要求完成相应的表演即可,角色的具体饰演者有导演来安排,代码如下所示。

public class Director {
    public void direct() {
        // 指定角色的饰演者
        GeLi geli = new LiuDeHua();
        // 注入具体饰演者到剧本中
        MoAttack moAttack = new MoAttack(geli);
        moAttack.cityGateAsk();
    }
}

  导演首先安排刘德华饰演革离,并将刘德华“注入”到《墨攻》剧本中,然后进行“城门叩问”剧情的演出工作。

2.2 属性注入

  属性注入可以有选择的通过setter方法完成调用类所需依赖的注入,更加灵活方便,代码如下所示。

public class MoAttack {
    private GeLi geli;

    // 属性注入方法
    public void setGeLi(GeLi geli) {
        this.geli = geli;
    }

    public void cityGateAsk() {
        geli.responseAsk("墨者革离!");
    }
}

  代码中为geli属性提供了一个Setter方法,以便让导演在需要时注入geli的具体饰演者,如下代码所示。

public class Director {
    public void direct() {
        MoAttack moAttack = new MoAttack();

        // 调用属性Setter方法注入
        GeLi geli = new LiuDeHua();
        moAttack.setGeli(geli);
        moAttack.cityGateAsk();
    }
}

  和通过构造函数注入革离饰演者不同,在实例化MoAttack剧本时,并未指定任何饰演者,而是实例化MoAttack后,在需要革离出场时,才调用setGeli()方法注入饰演者。

2.3 接口注入

  将调用类所有依赖注入的方法抽取到一个接口中,调用类通过实现该接口提供相应的注入方法。为了采取接口注入的方式,必须先声明一个ActorArrangable接口,接口如下:

public interface ActorArrangable {
    void injectGeli()
}

  MoAttack通过该接口提供具体的实现,代码如下。

public class MoAttack implements ActorArrangable{
    private GeLi geli;

    // 实现接口方法
    public void injectGeli(GeLi geli) {
        this.geli = geli;
    }

    public void cityGateAsk() {
        geli.responseAsk("墨者革离!");
    }
}

  Director通过ActorArrangable的injectGeli()方法完成饰演者的注入工作,代码如下。

public class Director {
    public void direct() {
        MoAttack moAttack = new MoAttack();
        GeLi geli = new LiuDeHua();
        moAttack.injectGeli(geli);
        moAttack.cityGateAsk();
    }
}

  由于通过接口注入需要额外声明一个接口,增加了类的数目,而且效果和属性注入并无本质区别,并不推荐这种注入方式。

3. 通过容器完成依赖属性关系的注入

  虽然MoAttack和LiuDeHua实现了解耦,MoAttack无须关注角色实现类的实例化工作,但这些工作中在代码中依然存在,只是转移到Director类中。现在,通过一个第三方的容器,帮助完成类的初始化与装配工作,让开发者从这些底层实现类的实例化,依赖关系装配等工作中解脱出来,专注于更有意义的业务逻辑开发工作。
  Spring就是这样的一个容器,它通过配置文件或注解描述类和类之间的依赖关系,自动完成类的初始化和依赖注入工作。当容器启动时,Spring根据配置文件的描述信息,自动实例化Bean并完成依赖关系的装配,从容器中即可返回准备就绪的Bean实例,后续可直接使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值