依賴註入的概念 當一個對象要調用另一個對象時,一般是new一個被調用的對象,示例: class A{ private B b=new B(); public void test(){ b.say(); } } A類的對象依賴於B類對象,如果沒有B類對象,A類對象就不能正常工作,稱A依賴於B。 以上方 ...
依賴註入的概念
當一個對象要調用另一個對象時,一般是new一個被調用的對象,示例:
class A{
private B b=new B();
public void test(){
b.say();
}
}
A類的對象依賴於B類對象,如果沒有B類對象,A類對象就不能正常工作,稱A依賴於B。
以上方式會增加類A與類B的耦合性,不利於項目後期的升級(擴展)、維護。
在Spring中,B類的實例(被調用者),不再由A類(調用者)創建,而是由Spring容器創建,創建好以後,由Spring容器將B類的實例註入A類對象中,稱為依賴註入(Dependency Injection,DI)。
原本是由A類主動創建B類對象(A類控制B類的創建),現在是Spring容器創建B類對象,註入A類對象中,A類被動接受Spring容器創建的B類實例,B類對象創建的控制權發生了反轉,所以又叫做控制反轉(Inversion of Control,IoC)。
依賴註入是一種優秀的解耦方式,由Spring容器負責控制類(Bean)之間的關係,降低了類之間的耦合。
因為Spring容器負責依賴註入(IoC),所以Spring容器也被稱為Spring IoC容器。
依賴註入有2種實現方式:
- 設值註入
- 構造註入
設值註入
通過主調類的setter()方法註入被調類的實例。一個參數即一個依賴對象。
1、分別寫2個介面
1 public interface Student { 2 public String getName(); 3 }
1 public interface Teacher { 2 public void say(); 3 }
2、分別寫2個實現類
1 public class BadStudent implements Student { 2 private String name; 3 4 public BadStudent(String name){ 5 this.name=name; 6 } 7 8 @Override 9 public String getName(){ 10 return name; 11 } 12 }
1 public class MathTeacher implements Teacher{ 2 private Student student; 3 4 //主調者的setter()方法,接受被調者實例 5 public void setStudent(Student student){ 6 this.student=student; 7 } 8 9 @Override 10 public void say() { 11 System.out.println(student.getName()+",叫家長來一下。"); 12 } 13 }
類與介面耦合。
3、在applicationContext.xml文件中配置Bean
1 <!-- 初始化BadStudent類的實例lisi--> 2 <bean name="lisi" class="beans.BadStudent"> 3 <constructor-arg value="李四" /> <!--向BadStudent的構造函數傳遞”李四“--> 4 </bean> 5 6 <!--配置依賴--> 7 <bean name="mathTeacher" class="beans.MathTeacher"> 8 <property name="student" ref="lisi" /> <!--name指定setter方法的形參,ref或者value指定實參:某個Bean的name--> 9 </bean>
<constructor-arg>元素向該Bean的構造函數傳遞實參,一個<constructor-arg>傳遞一個實參,一個<bean>可配置多個<constructor-arg>,根據傳遞的實參個數來調用相應的構造函數。constructor-arg即構造器參數。
實參值通過value或ref屬性來指定。value指定的是Java基礎類型的參數,ref即reference(引用),指定依賴的其它Bean。
可通過屬性index指定該value是第幾個參數,預設從0自動遞增。
<property>屬性指定setter方法的實參。一個<property>指定一個參數,一個<bean>可帶有多個<property>子元素。
name屬性指定setter方法中的某個形參,實參由value或ref指定。
如果實參是某個Bean的實例,用ref指定,值是該Bean的name屬性值。
如果實參是Java的基礎類型(整型、浮點型、String等),用value指定(放在引號中),Spring容器會自動根據name的指定形參的類型,將實參轉換為相應的類型進行賦值。
4、寫一個測試類
1 public class Test { 2 public static void main(String[] args) { 3 ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); 4 MathTeacher mathTeacher=applicationContext.getBean("mathTeacher",MathTeacher.class); 5 mathTeacher.say(); 6 } 7 }
看到控制台已經列印出了“李四,叫家長來一下。”。
構造註入
通過構造函數註入。
1、上面的代碼,將MathTeacher類修改如下
1 public class MathTeacher implements Teacher{ 2 private Student student; 3 4 //主調者的構造方法 5 public MathTeacher(Student student){ 6 this.student=student; 7 } 8 9 @Override 10 public void say() { 11 System.out.println(student.getName()+",叫家長來一下。"); 12 } 13 }
不使用setter方法註入依賴的對象,而是使用構造函數註入依賴的對象。
2、修改Spring容器的配置如下
1 <!-- 初始化BadStudent類的實例lisi--> 2 <bean name="lisi" class="beans.BadStudent"> 3 <constructor-arg value="李四" /> 4 </bean> 5 6 <!--配置依賴--> 7 <bean name="mathTeacher" class="beans.MathTeacher"> 8 <constructor-arg name="student" ref="lisi" /> 9 </bean>
3、運行,看到控制台列印出“李四,叫家長來一下。”。
說明
- 這兩種方式都可以註入Java的自帶的數據類型。
-
value是註入Java的基礎類型,ref是註入依賴的Bean。當然也可以用<value>、<ref>子元素的形式配置。