IoC(Inversion of Control),直观地讲,就是对象建立或查找对象依赖的控制权由应用代码转到了外部容器,控制权的转移是所谓反转。使用Ioc,一个对象依赖的其它对象会经过被动的方式传递进来,而不是这个对象本身建立或者查找依赖对象。咱们能够认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它html
IoC还有另一个名字——“依赖注入DI(Dependency Injection)”。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,形象地说,即由容器动态地将某种依赖关系注入到组件之中。java
上面说的可能有点晕,来一个实际点的例子。程序员
丽萨已经老大不小了,一直没有男友,看着别人恩恩爱爱的,也不由想找个BoyFriend。摆在她面前的有3种方案:主动“邂逅” Or 同事介绍 Or 父母包办。她会选择哪一种呢?spring
主动“邂逅”方式,如图所示:app
public class Girl { public void kiss(){ Boy boy = new Boy(); } }不过这种美好的纯洁的爱情,通常只会发生在校园里,对于已是工薪阶层的丽萨显然不太适合。
第二方案,同事介绍,函数
public class Girl { void kiss(){ Boy boy = BoyFactory.createBoy(); } }
不少人都是这样找到了本身的另外一半。丽萨之前也试着去跟同事介绍的handsome man接触过,可是真人与介绍的出入太大,最起码handsome这条就不太符合,并且有他许多缺点。以为他不适合本身,因此最后也就不了了之。this
因此无奈之下,她的难题丢给了父母。父母给她物色了一个“绝世好男人”——曾小贤(这娃有句经典台词:“好男人就是我,我就是....曾小贤”),终于算是遂了她的心愿了。spa
public class Girl { void kiss(Boy boy){ // kiss boy boy.kiss(); } }
虽然在现实生活中咱们都但愿与本身的另外一半来场完美的邂逅,但在Spring世界里,跟丽萨同样,选择的倒是父母包办,它就是控制反转,而这里具备控制力的父母,就是Spring所谓的容器概念。 code
典型的IoC能够如图所示。
xml
IoC有3种注入方式:接口注入、Setter方法注入、构造器注入。因为接口注入不推荐使用,因此只介绍setter方法注入和构造器注入。
用代码来讲明一切吧:
【Girl.java】
package com.tgb; /** * 期待找BF的Girl * @author Admin * */ public class Girl { private Boy bf; public Girl(){} public Girl(Boy bf){ System.out.print("使用构造方法方式注入:"); this.bf = bf; } public void setBf(Boy bf) { System.out.print("使用Setter方式注入:"); this.bf = bf; } public void kissYourBF() { bf.kiss(); } }【Boy.java】
package com.tgb; /** * 合格的BF * @author Admin * */ public class Boy { public void kiss(){ System.out.println("My boy friend,I'll kiss you!"); } }【Client客户端】
package com.tgb; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Client { public static void main(String[] agrs){ ApplicationContext factory = new ClassPathXmlApplicationContext("applicationContext.xml"); Girl lisa = (Girl)factory.getBean("girl"); lisa.kissYourBF(); } }【applicationContext.xml配置文件】
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"> <bean id="boy" class="com.tgb.Boy" /> <bean id="girl" class="com.tgb.Girl"> <!--构造器注入--> <constructor-arg ref="boy"></constructor-arg> <!--Setter方法注入--> <!--<property name="bf" ref="boy"></property>--> </bean> </beans>
Setter方法注入时,有2种装载方式须要注意,byName和byType。当我在配置文件中,把2种注入方式都注释掉,同时添加了default-autowire="byType",
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd" default-autowire="byType" > <bean id="boy" class="com.tgb.Boy" /> <bean id="girl" class="com.tgb.Girl"> <!--构造器注入--> <!--<constructor-arg ref="boy"></constructor-arg>--> <!--Setter方法注入--> <!--<property name="bf" ref="boy"></property>--> </bean> </beans>
执行结果如图:
可是换成default-autowire="byName",则会报以下错误:
这是为何呢?缘由在于,当使用byType方式装载时,Spring是根据classType来肯定要实例化的类。因此就算bean的id是boy,跟Girl中bf的Setter名字不一致,依旧能够实例化。可是使用byName时,则是根据id来实例化类的。因此只要把Boy类对应的bean id跟Girl中的setter方法名一致才行,即修改id="boy"为id="bf",便可正常显示:
<bean id="bf" class="com.tgb.Boy" /> <bean id="girl" class="com.tgb.Girl"> <!--构造器注入--> <!--<constructor-arg ref="boy"></constructor-arg>--> <!--Setter方法注入--> <!--<property name="bf" ref="boy"></property>--> </bean>
另外一种修改方式就是用显示的方式来设定Setter方法所注入的是哪一个类的对象:
<bean id="boy" class="com.tgb.Boy" /> <bean id="girl" class="com.tgb.Girl"> <!--构造器注入--> <!--<constructor-arg ref="boy"></constructor-arg>--> <!--Setter方法注入--> <property name="bf" ref="boy"></property> </bean>执行结果如图:
Setter 注入:
构造器注入: