Spring 的 IOC 容器讲解

 控制反转 IoC(Inversion of Control) : ioc 是一种编程思想,主要是协调各组件间相互的依赖关系。 Ioc 就是由容器来控制业务对象之间的依赖关系,而非传统方式中由代码来直接操控,控制反转的本质,是控制权由应用代码转到了外部容器,控制权的转移即是所谓的反转,控制权的转移带来的好处就是降低了业务对象之间的依赖程度,即实现了解耦。

       对象的创建一共有三种:自己创建,工厂模式创建,外部注入。对应三个动词: new , get , set

       New --- 自己创建

       Get --- 工厂模式

 

优点:实现了对象的统一创建,调用者无须关心对象创建的过程,只管从工厂中取得即可

 

     Set--- 外部注入

 

       Ioc 模式的优缺点

       优点:

IOC 把对象放在了 XML 中定义,所以当我们需要换一个实现子类将会变得很简单(一般这样的对象都是实现于某种接口的),只要修改 XML 就可以了。

       缺点:

<!-- [if !supportLists]-->l         <!-- [endif]-->生成一个对象的步骤变的复杂了,对于不习惯这种方式的人,会觉得有些别扭和不直观。不过这种复杂都已经被容器实现了,对于使用现有的 IOC 容器进行应用开发的人员来说,使用确实相当简单。

<!-- [if !supportLists]-->l         <!-- [endif]-->对象生成因为是使用反射编程,在效率上有些损耗。但相对于 ioc 提高的维护性和灵活性来说,这点损耗是微不足道的。

 

Spring 的 IOC 容器配置详解

            依赖注入 DI(dependency injection) 模式

类型名称

类型名称

描述

项目

Type1

接口注入

服务需要实现专门的接口,通过接口,有对象提供这些服务。

J2EE,

Type2

构造注入

使依赖性以构造函数的形式提供,不以 javabean 属性的形式公开

Spring

Type3

设置注入

通过 javabean 的属性(例如 setter 方法)分配依赖性

Spring

 

1.         <!-- [endif]-->type1 接口注入

我们开发一个 InjectUserDao 接口,它的用途是将一个 UserDao 实例注入到实现该接口的类中。

InjectUserDao 接口 代码如下:

Java代码
  1. public interface InjectUserDao {   
  2.   
  3.   
  4.         public void setUserDao(UserDao userDao);   
  5.   
  6.   
  7. }   
  8.   
  9.   
  10. UserRegister需要容器为它注入一个UserDao的实例,则它必须实现InjectUserDao接口。UserRegister部分代码如下:   
  11.   
  12.   
  13. public class UserRegister implements InjectUserDao{   
  14.   
  15.   
  16.         private UserDao userDao = null;//该对象实例由容器注入   
  17.   
  18.   
  19.             public void setUserDao(UserDao userDao) {   
  20.   
  21.   
  22.                 this.userDao = userDao;   
  23.   
  24.   
  25.             }   
  26.   
  27.   
  28. // UserRegister的其它业务方法   
  29.   
  30.   
  31. }   
  32.   
  33.   
  34. 2.  type2 构造注入   
  35.   
  36.   
  37. public class SetStudent {   
  38.   
  39.   
  40.     private Problem problem;   
  41.   
  42.   
  43.         public Student(Problem problem) {   
  44.   
  45.   
  46.             this.problem = problem;   
  47.   
  48.   
  49. }   
  50.   
  51.   
  52.         public void resolveProblem() {   
  53.   
  54.   
  55.             System.out.print(problem.displayMessage()+"\r");   
  56.   
  57.   
  58.     }   
  59.   
  60.   
  61. }  
public interface InjectUserDao {   	 	public void setUserDao(UserDao userDao);}UserRegister需要容器为它注入一个UserDao的实例,则它必须实现InjectUserDao接口。UserRegister部分代码如下:public class UserRegister implements InjectUserDao{   	 	private UserDao userDao = null;//该对象实例由容器注入    		public void setUserDao(UserDao userDao) {        		this.userDao = userDao;    		}// UserRegister的其它业务方法}2.	type2 构造注入public class SetStudent {	private Problem problem;		public Student(Problem problem) {			this.problem = problem;}		public void resolveProblem() {			System.out.print(problem.displayMessage()+"\r");	}}

 对应的配置文件:

 

 

对应的配置文件代码
  1. <bean id="Problem" class="com.example1.Problem">   
  2.   
  3.   
  4.         <property name="title" >   
  5.   
  6.   
  7.             <value>problem title</value>   
  8.   
  9.   
  10.         </property>   
  11.   
  12.   
  13.     </bean>   
  14.   
  15.   
  16.     <bean id="Student" class="com.example1.Student">   
  17.   
  18.   
  19.         <constructor-arg ref="problem"></constructor-arg>   
  20.   
  21.   
  22.     </bean>  
<bean id="Problem" class="com.example1.Problem">		<property name="title" >			<value>problem title</value>		</property>	</bean>	<bean id="Student" class="com.example1.Student">		<constructor-arg ref="problem"></constructor-arg>	</bean>

  3.    type3 设值注入

Java代码
  1. 3.  type3 设值注入   
  2. public class SetStudent {   
  3.     private Problem problem;   
  4.     public Problem getProblem() {   
  5.         return problem;   
  6.     }   
  7.     public void setProblem(Problem problem) {   
  8.         this.problem = problem;   
  9.     }   
  10.     public void resolveProblem() {   
  11.         System.out.print(problem.displayMessage()+"\r");   
  12. }   
  13. }  
3.	type3 设值注入public class SetStudent {	private Problem problem;	public Problem getProblem() {		return problem;	}	public void setProblem(Problem problem) {		this.problem = problem;	}	public void resolveProblem() {		System.out.print(problem.displayMessage()+"\r");}}

 对应的配置文件:

Xml代码
  1. <bean id="ProblemA" class="com.example1.ProblemA">  
  2.         <property name="title" >  
  3.             <value>problem title</value>  
  4.         </property>  
  5.     </bean>  
  6.   
  7. <bean id="ProblemB" class="com.example1.ProblemB">  
  8.         <property name="title" >  
  9.             <value>problem title</value>  
  10.         </property>  
  11.     </bean>  
  12.        
  13.     <bean id="Student" class="com.example1.Student">  
  14.         <property name="problem" ref="ProblemA" />  
  15.     </bean>  
  16.   
  17. <bean id="StudentA" class="com.example1.StudentA">  
  18.         <property name="problem" ref="ProblemA" />  
  19.     </bean>  
  20.   
  21. <bean id="StudentB" class="com.example1.StudentB">  
  22.         <property name="problem" ref="ProblemC" />  
  23.     </bean>  
<bean id="ProblemA" class="com.example1.ProblemA">		<property name="title" >			<value>problem title</value>		</property>	</bean><bean id="ProblemB" class="com.example1.ProblemB">		<property name="title" >			<value>problem title</value>		</property>	</bean>		<bean id="Student" class="com.example1.Student">		<property name="problem" ref="ProblemA" />	</bean><bean id="StudentA" class="com.example1.StudentA">		<property name="problem" ref="ProblemA" />	</bean><bean id="StudentB" class="com.example1.StudentB">		<property name="problem" ref="ProblemC" />	</bean>

 

3 种类型的对比

接口注入模式具有侵入性,一般情况不使用,这里不加说明

2.       <!-- [endif]-->type2 构造注入的优势

在构造期即创建一个完整、合法的对象 ” 。对于这条 java 设计原则, type2 无疑是最好的响应者

避免了烦琐的 setter 方法的编写,所有依赖关系均在构造函数中设定,依赖关系集中呈现,更加易读。

由于没有 setter 方法,依赖关系在构造时由容器一次性设定,因此组件在被创建之后对组件“不变”的稳定状态,无须担心上层代码在调用过程中执行 setter 方法对组件依赖关系产生破坏,特别是对于 singleton 模式的组件而言。这可能对整个系统产生重大的影响。

由于关联关系仅在构造函数中表达,只有组件创建者需要关心组件内部的依赖关系。对于调用者而言,组件中的依赖关系处于黑盒之中。对上层屏蔽不必要的信息,也为系统的层次清晰性提供了保证。

通过构造子注入,意味着我们可以在构造函数中决定依赖关系的注入顺序,对于一个大量依赖外部服务的组件而言,依赖关系的获得顺序可能非常重要。

设置注入的优势

对于习惯了传统的 javabean 开发的程序员来说,通过 setter 方法设定依赖关系显得更加直观。更加自然

如果依赖关系较为复杂, type2 模式的构造函数也会相当的庞大,这样 type3 模式往往更加简洁

对于某些第三方类库而言,可能要求我们的组件必须提供一个默认的构造函数。此时 type2 类型的依赖注入机制就体现出其局限性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值