spring依赖注入方式及其优缺点


Spring 能有效地组织J2EE应用各层的对象。不管是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO对象,都可在Spring的 管理下有机地协调、运行。

Spring将各层的对象以松耦合的方式组织在一起,Action对象无须关心Service对象的具体实现,Service对 象无须关心持久层对象的具体实现,各层对象的调用完全面向接口。当

系统需要重构时,代码的改写量将大大减少。

上面所说的一切都得宜于Spring的核心机制,依赖注入。依赖注入让bean与bean之间以配置文件组织在一起,而不是以硬编码的方式耦合在一起。理解依赖注入

依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,

被调用者)的协助时,在 传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用

者 实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。

本文研究Spring的三种依赖注入实现类型——接口注入(Interface Injection)、设值注入(Setter Injection)、构造子注入(Constructor Injection)。

Type1 接口注入: 传统的创建接口对象的方法, 借助接口来将调用者与实现者分离。如下面的代码所示:

1 public class ClassA
2 {
3 private InterfaceB clzB;
4 public doSomething()
5 {
6 Ojbect obj = Class.forName(Config.BImplementation).newInstance();
7 clzB = (InterfaceB)obj;
8 clzB.doIt();
9 }
10 ……
11 }


在代码中创建InterfaceB实现类的实例,并将该对象赋予clzB。也就是依据Java中的对象动态多态技术:InterfaceB clzB=new InterfaceBImpleClass();为了将调用者与实现者在

编译期分离,于是有了上面的代码,我们根据预先在配置文件中设定的实现类的类名(Config.BImplementation),动态加载实现类,并通过InterfaceB强制转型后为 ClassA所用。


Type2 设值注入: 在各种类型的依赖注入模式中,设值注入模式在实际开发中得到了最广泛的应用(其中很大一部分得力于Spring框架的
影响)。使用IoC的Setter注射,一些外部元数据被用于解决依赖性问题。并且在Spring中,这种元数据采取了简单的XML配置文件的形式。

下面为某个类的示例代码
(其中包含有一个message属性,该类通过其setMessage()方法获得右容器所提供的值。)

1 public class UpperAction implements Action
2 {
  private String message;
  public String getMessage()
  {
    return message;
  }
  public void setMessage(String string)
  {
10     message = string;
11   }
12 }
13
其中message 属性的值通过配置文件来提供

1 <bean id="theUpperAction" class="springj2seapp.UpperAction">
     <property name="message">
        <value>HeLLo,UpperAction </value>
    </property>
5 </bean>
6


Type3 构造器注入:即通过构造函数完成依赖关系的设定, 在Type3类型的依赖注入机制中,依赖关系是通过类构造函数建立,容器通过调用类的构造方法,将其所需的依赖关系

注入其中。
public class DIByConstructor {
private final DataSource dataSource;
private final String message;
public DIByConstructor(DataSource ds, String msg) {
this.dataSource = ds;
this.message = msg;
}


示例代码:
配置文件如下
1 <bean id="exampleBean" class="examples.ExampleBean">
2
  <constructor-arg>
4
5 <ref bean="anotherExampleBean"/>
6 </constructor-arg>
  <constructor-arg><ref bean="yetAnotherBean"/></constructor-arg>
  <constructor-arg type="int">
9 <value>1</value>
10 </constructor-arg>
11 </bean>
12 <bean id="anotherExampleBean" class="examples.AnotherBean"/>
13 <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
14

ExampleBean代码:

1 public class ExampleBean
2 {
    private AnotherBean beanOne;
    private YetAnotherBean beanTwo;
    private int i;
    public ExampleBean(AnotherBean anotherBean, YetAnotherBean yetAnotherBean,
                                                                    int i)
7 {
        this.beanOne = anotherBean;
        this.beanTwo = yetAnotherBean;
10         this.i = i;
11     }
12 }
13
当构造方法中带多个不同的基本数据类型的参数时,为了避免产生二义性,可以采用type或者index来指定构造方法的参数的类型和顺序。
如:
   type方法
1 <constructor-arg type="int">
2 <value>7500000</value>
3 </constructor-arg>
  <constructor-arg type="java.lang.String">
5 <value>42</value>
6 </constructor-arg>
7
    index方法
1 <bean id="exampleBean" class="examples.ExampleBean">
  <constructor-arg index="0">
3 <value>7500000</value>
4 </constructor-arg>
  <constructor-arg index="1">
6 <value>42</value>
7 </constructor-arg>
8 </bean>
9
总结:
     type1在灵活性、易用性上不如其他两种注入模式, Type2 和Type3型的依赖注入实现则是目前主流的IOC实现模式, Type3 和Type2模式各有千秋,而Spring都对Type3和

Type2类型的依赖注入机制提供了良好支持。 以Type3类型为主,辅之以Type2类型机制作为补充,可以达到最好的依赖注入效果,不过对于基于Spring Framework开发的应用而言

,Type2使用更加广泛。


Type3 构造器注入的优势:
1. “在构造期即创建一个完整、合法的对象”,对于这条Java设计原则,Type2无疑是最好的
响应者。
2. 避免了繁琐的setter方法的编写,所有依赖关系均在构造函数中设定,依赖关系集中呈现,
更加易读。
3. 由于没有setter方法,依赖关系在构造时由容器一次性设定,因此组件在被创建之后即处于
相对“不变”的稳定状态,无需担心上层代码在调用过程中执行setter方法对组件依赖关系
产生破坏,特别是对于Singleton模式的组件而言,这可能对整个系统产生重大的影响。
4. 同样,由于关联关系仅在构造函数中表达,只有组件创建者需要关心组件内部的依赖关系。
对调用者而言,组件中的依赖关系处于黑盒之中。对上层屏蔽不必要的信息,也为系统的
层次清晰性提供了保证。
5. 通过构造子注入,意味着我们可以在构造函数中决定依赖关系的注入顺序,对于一个大量
依赖外部服务的组件而言,依赖关系的获得顺序可能非常重要,比如某个依赖关系注入的
先决条件是组件的DataSource及相关资源已经被设定。
Type2 设值注入的优势
1. 对于习惯了传统JavaBean开发的程序员而言,通过setter方法设定依赖关系显得更加直
观,更加自然。
2. 如果依赖关系(或继承关系)较为复杂,那么Type2模式的构造函数也会相当庞大(我们需
要在构造函数中设定所有依赖关系),此时Type3模式往往更为简洁。
3. 对于某些第三方类库而言,可能要求我们的组件必须提供一个默认的构造函数(如Struts
中的Action),此时Type2类型的依赖注入机制就体现出其局限性,难以完成我们期望的功
能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值