實例說明Spring的2種注入方式

1、依賴注入

以往3種自主控制依賴關係注入的方式有:由bean自己來控制其實例化、直接在構造器中指定依賴關係、類似服務定位器模式。

DI主要有2種注入方式,即Setter注入和constructor注入。

1setter注入:在java類中爲屬性添加set方法,在配置文件配置

Company類定義如下:

public class Company {
    private int id;
    private String name;
    private Boolean chinese;
    private Person CEO;
….   get/set function …  }

Person類如下所示:

public class Person {
    private Integer id;
    private String name;
    private Integer age;
    private String email;
….   get/set function …  }

對應的XML文件applicationContext.xml配置如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="person"class="org.shirdrn.entity.Person" abstract="false"
   singleton="true" lazy-init="default"autowire="default"
   dependency-check="default">
   <property name="id">
      <value>1001</value>
   </property>
   <property name="name">
      <value>Shirdrn</value>
   </property>
   <property name="age">
      <value>26</value>
   </property>
   <property name="email">
      <value>[email protected]</value>
   </property>
</bean>
<bean id="companyBean"class="org.shirdrn.entity.Company"
   abstract="false" singleton="true"lazy-init="default"
   autowire="default"dependency-check="default">
   <property name="id">
      <value>2008</value>
   </property>
   <property name="name">
      <value>CNAET</value>
   </property>
   <property name="chinese">
      <value>true</value>
   </property>
   <property name="CEO">
      <ref bean="person" />
   </property>
</bean>
</beans>

測試的程序代碼如下:

public class Main {
public static void main(String[] args){
   ApplicationContext ctx = newFileSystemXmlApplicationContext("src/applicationContext.xml");
   Company c = (Company)ctx.getBean("companyBean");
   System.out.println("company's id         = "+c.getId());
   System.out.println("company'sname        = "+c.getName());
   System.out.println("company is Chinese    ="+c.getChinese());
   System.out.println("--- the following is CEO's detail---");
   System.out.println("CEO's id      ="+c.getCEO().getId());
   System.out.println("CEO's name    ="+c.getCEO().getName());
   System.out.println("CEO's age     ="+c.getCEO().getAge());
   System.out.println("CEO's Email   ="+c.getCEO().getEmail());  
}
}

測試輸出結果如下所示:

company's id          =2008
company's name        = CNAET
company is Chinese    = true
--- the following is CEO's detail ---
CEO's id      = 1001
CEO's name    = Shirdrn
CEO's age     = 26
CEO's Email   =

2、constructor注入

通過帶參數的構造器實現,還可以通過給靜態工廠方法傳參數來構造bean,在配置文件配置。

    <1>構造器實現

<bean id="exampleBean" class="examples.ExampleBean">
    <!-- constructor injection using the nested <ref/> element -->
  <constructor-arg><ref bean="anotherExampleBean"/></constructor-arg>
  <!-- constructor injection using the neater 'ref' attribute -->
  <constructor-arg ref="yetAnotherBean"/>
  <constructor-arg type="int" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
    private AnotherBean beanOne;
    private YetAnotherBean beanTwo;
    private int i;
    public ExampleBean(
        AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
        this.beanOne = anotherBean;
        this.beanTwo = yetAnotherBean;
        this.i = i;
    }
}

    <2>靜態工廠實現

<bean id="exampleBean" class="examples.ExampleBean"
      factory-method="createInstance">
  <constructor-arg ref="anotherExampleBean"/>
  <constructor-arg ref="yetAnotherBean"/>
  <constructor-arg value="1"/> 
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>  

public class ExampleBean {
    //私有的構造器
    private ExampleBean(...) {... }
    //靜態工廠方法;方法參數由constuctor-arg元素提供,方法內對象的構造參數依賴於
         工廠方法參數,但不必全部使用.
    public static ExampleBean createInstance (
            AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
        ExampleBean eb = new ExampleBean (...);
        // some other operations...
        return eb;
    }
} 

    【工廠方法返回的實例類型並不一定要與包含該靜態方法的類類型一致!!

       如果是非靜態的實例工廠方法,則配置bean時使用factory-bean而不是class屬性,其餘相同。】

二者如何選擇:

<1>大量的constructor參數會使程序變得笨拙,特別是某些屬性可選時。因此Spring開發團隊提倡使用setter注入。而且setter注入在以後某個時候還可以對實例重新配置。

<2>constructor注入一次性將所有依賴注入的做法意味着在未完全初始化的狀態下,此物件不會返回給客戶代碼(或被呼叫),此外物件也不可能再次被重新配置。

<3>由於setter注入提供set方法,所以不能保證相關的成員或資源在執行時期不會被更改設定,所以如果想要讓一些成員或資源變爲只讀或私有,則使用constructor是簡單的選擇。對於沒有原始碼的第三方類,或者沒有提供setter方法的遺留代碼,只能使用constructor注入。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章