IT Notes‎ > ‎Java‎ > ‎Java Web / Java EE‎ > ‎Spring Framework‎ > ‎

Spring DI(Dependency Injection)

IoC, Inversion of Control, 控制反转,是 DI 的同义语。可以理解为:DI 是操作方式,IoC 的操作结果。IoC 也是 DIP (Dependency Inversion Principle, 依赖倒转原则)的一个体现,关于依赖倒转严宏《Java 设计模式》中也有谈到。

要理解「依赖注入」,首先需要理解 OO 的「依赖关系」:类 A 中的某方法的入口参数中使用到类 B,则认为 A 依赖于 B. 如「人」类有一个方法「吃饭」,需要用到「碗」类,那么可以认为:「人」类依赖于「碗」类。具体可以参考本站的《类图——依赖关系》。
person needs bowl
如果不使用 Spring DI, 则可能有如下代码:
Person person = new Person();
Bowl bowl = new Bowl();

person.setBowl(bowl); // 设置依赖关系
person.eat();

但如果使用 Spring DI, 则以上两对象的创建和依赖关系设置,都由 Spring 容器代劳,对应用程序员来说,就是设置一下容器的配置文件,具体可以参考 HelloWorld 的做法。应用程序中,需要相关对象,从容器中获取就可以了:
Person person = context.getBean("person", Person.class);
person.eat();

Spring 通过容器管理类的依赖关系,当 A 依赖于 B,并不需要在程序中写上 new B() 这样的语句去生成 B 对象,而是通过 Spring 的容器管理和生成 B 对象,再注入到 A 中。刚才的例子说明也说明了这个道理。由此可见,Spring DI,是对寻找对象的一次革命,再也不需要 new B() 这种方式了,让 new 见鬼去吧!

注入方式

在使用 Spring 实现 DI 时,具体有几种注入方式:设值注入(Setter-based DI),构造注入(Constructor-based DI),接口注入等。 

1. 设值注入

设置注入又称方法注入,它通过 setter。一般实际开发中基本上用的都是这种。
该方式可注入简单的属性值,也可以注入对象实例。
HelloWorld 的例子里即用这种方式注入了一个简单的属性。
     <bean id="young" class="hello.YoungMan">
          <property name="phone" ref="mobile" />
     </bean>

2. 构造器注入

构造注入,通过构造方法注入依赖目标。配置文件片段举例如下
     <bean id="old" class="hello.OldMan">
          <constructor-arg ref="traditional"></constructor-arg>
     </bean>
     

3. 接口注入

TODO,基本上用不到。这里暂时不记录。
构造方法和接口注入两种用的比较少。

关于注入的配置文件的一些问题

name 和 id

<bean id='...' class='...'/>, <bean name='...' class='...'/>
两种方式都可以,但 name 中可以包含特殊字符,而 id 不可以

bean 的生存范围(scope)

singleton / prototype / request / session / global session / application
  • signleton, 在整个 Spring DI 容器中,如果 scope="signleton",则该 bean 将只有一个实例。
  • prototype, 每次 getBean 都通过原型复制产生一个新的 bean
  • request / session / global session / application, 只在 Web 应用中有效

自动装配 auto wire

该功能在合适的地方使用就好,在生产环境和较大的应用中,并不推荐使用自动装配!
<bean ... autowire="autodectect/byName/byType/constructor/default/no"/>
其中 byType 是 annotation 的默认方式

生命周期

<bean /> 的两个属性:
lazy-init 如果设置为 true,容器加载时,将不会初始化。基本上用不到的特性,但如果应用启动特别慢,可以考虑使用这个属性
init-method 属性:启动容器时,调用的方法
destroy-method 属性:关闭容器时,调用的方法,不能和 prototype 属性连用,因连用时,看不到 destroy-method 对应的方法的执行情况。prototype 属性的 bean 在创建后,Spring 容器就不负责管理了,生死由它自己。



Comments