控制反轉(IoC:Inversion of Control)是Spring框架的核心,主要用來減少對象間的耦合問題。Martin Fowler曾提問:哪方面的控制被反轉了?他總結是依賴對象的獲得被反轉。因此,他給控制反轉提出一個更貼切的名字:依賴注入。Spring的優勢是通過一個IoC容器,管理所有的JavaBean,自動注入依賴對象間的引用,減輕程序員的負擔。下面通過一個簡單的實例,理解Spring中IoC的優勢和原理。
一個parent有兩個children,一個son和一個daughter。parent每次出去玩的時候,只能帶上一個小孩,因此只能輪流地和他們玩。他們的類的實現如下:
抽象類Child:
public abstract class Child {
public abstract void play();
}
Child的子類Son:
public class Son extends Child {
@Override
public void play() {
// TODO Auto-generated method stub
System.out.println("Parent is playing with the son!");
}
}
Child的子類Daughter:
public class Daughter extends Child {
@Override
public void play() {
// TODO Auto-generated method stub
System.out.println("Parent is playing with the daughter!");
}
}
類parent:
public class Parent {
private Child child;
public Child getChild() {
return child;
}
public void setChild(Child child) {
this.child = child;
}
public void playWithChild() {
child.play();
}
}
有如下兩種應用場景需求:
情況一:parent帶son出去玩
情況二:parent帶daughter出去玩
下面比較兩種實現方法:
實現方法一:常規實現
import org.junit.Test;
import junit.framework.TestCase;
public class ParentTest extends TestCase {
@Test
public void testPlayWithChild() {
Parent parent = new Parent();
// 情況一:
// 如果Parent和Son玩,則創建Son實例,並調用屬性方法傳遞引用
Son son = new Son();
parent.setChild(son);
// 情況二:
// 如果Parent和Daughter玩,則創建Daughter實例,並調用屬性方法傳遞引用
// Daughter daughter = new Daughter();
// parent.setChild(daughter);
parent.playWithChild();
}
}
實現方法二:IoC實現
beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!--
情況一:Parent帶Son出去玩
-->
<bean id="child" class="Son">
</bean>
<!--
情況二:Parent帶Daughter出去玩
<bean id="child" class="Daughter"> </bean>
-->
<bean id="parent" class="Parent" autowire="byType">
</bean>
</beans>
JUnit測試程序:
import org.junit.Test;
import junit.framework.TestCase;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ParentTest extends TestCase {
@Test
public void testPlayWithChild() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
Parent parent = (Parent) ctx.getBean("parent");
parent.playWithChild();
}
}
兩種實現方式的比較:
1. 常規方法中,parent依賴的child引用,通過調用屬性方法來傳遞;IoC實現中,通過byType由IoC容器自動注入parent所依賴的引用。
2. 常規方法除了要創建實例,還要手動傳遞parent依賴的對象的引用;IoC只需要修改xml配置文件
3. 測試代碼中紅色標記部分,表示針對兩種情況需要改動的代碼。IoC明顯要簡單、靈活、方便。