趣解Spring-Ioc的含义及注入方式

场景介绍

为了更好的说明Ioc注入方式,我们先想象一个场景:《喜剧之王》大家应该都看过,周星驰在里面饰演尹天仇,里面有一段戏可谓经典,周星驰扮演送外卖的卧底给黑社会人员送外卖被识破,无奈说了一句:“我真的只是个送外卖的!”,在程序里面,首先我们会想到这样实现:

public class Comedy{
    public void action{
        ZhouXingChi zxc = new ZhouXingChi();
        zxc.say("我真的只是个送外卖的");
    }
}

这里面其实有个问题,就是周星驰这个演员直接侵入了剧本(Comedy),使剧本和演员直接耦合在了一起,而正常的剧本肯定是围绕具体角色(尹天仇)而展开,在剧本投入拍摄时候选取最适合的演员才对,而非绑定到一个具体的人身上。改进后我们会想到使用接口实现,为剧本的主人公尹天仇定义一个接口,通过接口实现者引入演员:

public class Comedy{
    public void action{
        //通过接口引入尹天仇
        YinTianChou ytc = new ZhouXingChi();
        //通过接口展开剧情
        ytc.say("我真的只是个送外卖的");
    }
}

这样的好处就是,剧本的情节依赖于角色展开,在具体拍摄时角色由演员饰演。这样看似美好,其实剧本类还是依赖于YinTianChou接口和ZhouXingChi类,并未实现剧本和演员解耦。要想实现这个,我们还需要一个导演,导演的工作是将演员安排到角色上,导演负责剧本、角色和演员的协调工作。对应到我们的程序里,导演就像一台装配器,安排演员去饰演角色。

接下来以这个例子为引子,我们了解下Ioc:Ioc(Inverse of Control)的意思是控制反转,这包含两个含义,一方面是控制,其二是反转。那么什么东西的“控制”被“反转”了呢?回想刚才的例子,控制是指角色YinTianChou的饰演者的控制权,反转是指这种控制权从《喜剧之王》剧本中解除,交到导演手中,即某一接口具体实现类的选择权从调用类中移除,转交给第三方即Spring容器通过Bean配置来进行控制,Ioc说是控制反转,其实不如说是依赖注入来的好理解。接下来说下如何实现注入:

Ioc注入方法

Ioc注入方法有三种:构造函数注入、属性注入和接口注入。其中接口注入不常用,我们重点说下前两种:

1.构造函数注入

以上述例子开始,通过调用类的构造函数,将接口实现类传入。

public class Comedy{
    private YinTianChou ytc;
    //通过构造函数注入具体饰演者
    public Comedy(YinTianChou ytc){
        this.ytc=ytc;
    }
    public void action{
        ytc.say("我真的只是个送外卖的");
    }
}

这样,Comedy的构造函数无须关心谁来饰演角色,即只要实现YinTianChou接口的实现类都可以,角色的饰演者由导演制定:

public class Director{
    public void direct(){
        //指定角色饰演者
        YinTianChou ytc = new ZhouXingChi();
        //注入饰演者到剧本
        Comedy comedy = new Comedy(ytc);
        comedy.action();
    }
}

这样就实现剧本和演员解耦。但是考虑一个情况,就是虽然尹天仇是喜剧之王的主要角色,但是并非所有时间都需要尹天仇参演(不然配角、龙套怎么混饭吃),这时候通过构造函数将其注入到剧本就不合适了,我们需要用属性注入

2.属性注入

属性注入即通过setter方法完成调用类依赖的注入,更加灵活:

public class Comedy{
    private YinTianChou ytc;
    //通过属性注入具体饰演者
    public void setYinTianChou(YinTianChou ytc){
        this.ytc=ytc;
    }
    public void action{
        ytc.say("我真的只是个送外卖的");
    }
}

这样导演就可以在需要的时候注入YinTianChou的具体饰演者:

public class Director{
    public void direct(){
        //指定角色饰演者
        YinTianChou ytc = new ZhouXingChi();
        Comedy comedy = new Comedy();
        //属性注入
        comedy.setYinTianChou(ytc);
        comedy.action();
    }
}

这样在实例化Comedy时,没有指定任何饰演者,配角、龙套可以演戏,当需要尹天仇出场时,调用setert方法注入饰演者周星驰。但这样是不是很完美呢?

通过容器完成依赖注入

上述例子中虽然Comedy和ZhouXingChi实现了解耦,Comedy无须关注角色实现类的实例化,但是并不是不需要做这个工作,只是交给了导演类而已,为了改变这一局面,我们需要一种机制,在这个例子中我们可以举办一场“全民投票”,由媒体投票决定谁当导演、谁当演员,这样剧本、演员、导演都实现了解耦。这个“全民投票”或者说第三方代理机构在程序上我们称为第三方的容器,这个容器帮助我们完成类的初始化和装配,帮助我们实例化类并解决依赖关系。Spring就是这样一个容器,spring通过配置文件或注解描述类之间的依赖关系,自动完成类的初始化和依赖注入。
我们只需要在配置文件中加入:

<!— 实现类实例化—>
<bean id=“ytc" class=“ZhouXingChi”/>
<!— 通过geli-ref建立依赖关系—>
<bean id="Comedy" class =“com.xxx.Comedyk”
p:geli-ref="ytc”/>

至此,完美解决了上述问题,spring的强大也初露锋芒。至于spring为什么能实现这个功能,依赖的是java的反射功能。有兴趣的大家可以继续深入学习!

参考《Spring+4.x++企业应用开发实战》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值