Spring知识整理(二) —— IoC概念

    IoC(控制反转),又称DI(依赖注入),是Spring的核心和灵魂。所谓的IoC,当你对Spring有一定了解的时候,可以将它简单的理解为实例的成员注入交由Spring容器控制,或者说成员依赖Spring容器注入到实例中。
    那么究竟什么是IoC,首先可以记住一句话,就是好莱坞原则:“Don’t call us, we will call you.”然后我们通过用以下的例子对IoC进行简单说明:
假设我们现在需要做一个关于装配汽车的应用,那么我们就需要一个名字类似于Car的一个类,在这个类中会有诸如wheel(轮胎)、engine(发动机)等成员。
    那么在通常的Java应用中,我们一般会这样装配一个Car的实例:
    Car myCar = new Car();
    myCar.setWheels(…);
    myCar.setEngine(…);
    …
    或者这样:
    Car myCar = new Car(Arrays.asList(wheel…), engine, …);
    再或者工厂方法等等的方式去初始化一个Car,总之就是将Car中各个成员的装配写在代码中,而Car中的各个成员也是自定义的类,所以也要初始化并加装成员。这样如果代码不经过优化,当我们需要一辆Car的时候就需要从底层到顶层一步步的初始化成员,然后一个个set到对应实例中,代码就会很臃肿。还有个问题,就是当我们要将一辆已经装配好的Car的轮胎换成另一个品牌时,我们就需要找到这个Car初始化的代码,找到轮胎初始化的地方,然后更改代码,如果这种Car在100个地方初始化过,那就会是场灾难,这也就是所谓耦合带来的问题。
    说了这么多想到底要说明什么,就是说在一般的简单应用中,类成员的加载,或者说是控制是由代码完成的,一般是由构造器或setter方法完成。而对于Car来说,一辆汽车必须有一个发动机,否则不能称之为汽车,那我们就可以说Car是依赖于Engine类的,Engine可以叫做Car的依赖类。
    Ok,现在两个名词各解释了一半了,控制和依赖都很简单理解,那什么叫反转和注入呢。继续上边的例子,我们希望修改的代码尽可能少,并且松散耦合,我们可以先准备一个仓库,里面有各种Engine和Wheel的实现,再将Engine和Wheel类抽象出父类,这样实现方法就可以返回统一的类型,这样在装配Car的时候只要调用仓库内不同的方法就可以直接初始化成员。
    好吧这还不够,毕竟我们的Car的初始化还是会分散在各个地方,那么我们为何不将Car的初始化统一起来,工厂方法是一个好的选择,但是工厂方法的接口变动还是会引起很多问题。
    其实对于这个应用,我们只关心汽车的各个零件是什么厂家生产的什么型号的零件,至于零件怎么来的,由怎么装上的都可以隐藏掉,那么我们能否只对一个类似于配置单的东西做文章而不关心底层实现。
    答案是可以的,这也正是Spring IoC所做的事情,而IoC中的反转就是说上述的控制全部交由IoC Service Provider完成,而DI的意思就是依赖的注入由Spring容器完成。
IoC主要有三种注入方式:构造方法注入(constructor injection)、setter方法注入(setter injection)以及接口注入(interface injection)。
    前两中在上述例子中已经已经有过说明,至于接口注入就相当于我们最后说的抽象出一个父类,然后根据这个父类注入其子类。只不过这里是根据接口来注入,这样可以避免Java单继承带来的麻烦。不过接口注入的方式并不被提倡,其侵入性(需要实现不必要的接口)使其处于“退役状态”。
    构造方法注入和setter方法注入最主要的区别就是对象在构造完成后能否马上处于就绪状态(可以马上使用),其他方面构造方法注入有着更多的缺陷,比如当依赖较多时,构造器的参数列表会很长;而通过反射构造对象时,对同类型参数的处理比较困难,维护和使用上也比较麻烦;而且在Java中,构造器无法被继承,无法设置默认值;对于非必须的依赖处理,可能需要引入多个构造器,而参数数量的变动可能造成维护上的不便。而setter注入就不会有上述问题。

猜你喜欢

转载自z-rabbit.iteye.com/blog/1852205