1. 程式人生 > >控制反轉與依賴注入

控制反轉與依賴注入





【 Spring IoC Container 使用步驟 (非Web環境) 】


1、Configuration metadata 

可以使用 XML 檔案,比如 container.xml 

可以使用註解

2、建立容器:

// 在 指定配置檔案時可以使用 Ant 風格的萬用字元
final String configLocations = "classpath:org/**/container.xml";
ApplicationContext container = new ClassPathXmlApplicationContext( configLocations ) ;

ApplicationContext 是個介面

final String configLocations = "classpath:org/**/container.xml";
AbstractApplicationContext container = new ClassPathXmlApplicationContext(configLocations) ;

AbstractApplicationContext 是個抽象類,其中定義了 close() 方法


3、從容器中獲取 Bean

ClassName  x = container.getBean( "bean-id" , ClassName.class ) ;

其中 bean-id 是指 XML 檔案中 或 註解中 為 Bean 指定的 id

其中 ClassName 是指 Bean 的型別,比如 org.malajava.container.Person



4、關閉容器 (優秀是一種習慣)

container.close() ; //  AbstractApplicationContext 是個抽象類,其中定義了 close() 方法


【 控制反轉 ( Inversion of Control , IoC ) 】


使用一個 Person 型別的物件:

[ Java ] 

Date date = new Date();

Person p = new Person();
p.setId( 9527 ) ;
p.setName( "華安" );
p.setGender( '男' );
p.setBirthdate( date ) ; // 引用另外一個物件

System.out.println( p.getId() + " : " + p.getName() + " , " + p.getGender() );

[ IoC ] 
 
<bean id="date" class="java.util.Date" />


<bean id="person" class="org.malajava.container.Person">
<property name="id" value="9527" />
<property name="name" value="華安" />
<property name="gender" value="男" />
<property name="birthdate" ref="date" />
</bean>

Person p = container.getBean( "person" , Person.class );
    System.out.println( p.getId() + " : " + p.getName() + " , " + p.getGender() );

【 依賴注入 ( Dependency Injection , DI ) 】


1、基於 setter 的注入方式 ( Spring 支援 ) [主要應用方向]

對於"簡單型別"來說可以使用以下形式注入:

        <property name = "屬性名"  value = "字面量"  />
       
        或
       
        <property name="屬性名" >
<value>字面量</value>
</property>

         所謂"簡單型別"是指:
         8種基本資料型別及其包裝類型別的屬性
          byte -->  Byte 
          short --->  Short 
          int --->  Integer 
          long -->  Long
          float --->  Float 
          double ---> Double
          char ---->  Character
          boolean --->  Boolwan
         java.lang.String

   對於其他的引用型別的屬性來說,要使用以下形式注入:
   
   <property name = "屬性名"  ref = "所引用的Bean的id"  />
   
   或
   
   <property name="屬性名" >
<ref bean="所引用的Bean的id" />
</property>
   
  Spring Framework 3.x 開始支援 p 名稱空間 ( namespace ):
  
  首先需要在 xml 檔案中引入 p 名稱空間:
  xmlns:p="http://www.springframework.org/schema/p"
  
    對於 "簡單型別" 的屬性來說,可以使用以下形式注入:
    <bean  id="...."  class="...."   p:屬性名 = "屬性值" />
   
    對於其他的引用型別的屬性來說,要使用以下形式注入:
    <bean  id="...."  class="...."   p:屬性名-ref = "屬性值" />

2、基於構造方法的注入方式  ( Spring 支援 )

<bean id="student" class="org.malajava.injection.Student" >
<constructor-arg name="name" value="郭襄" />
<constructor-arg name="id" value="1" />
<constructor-arg name="number" value="1003" />
<constructor-arg name="gender" value="女" />
<constructor-arg name="birthdate" ref="date" />
<constructor-arg name="married" value="false" />
</bean>

注意:
a>、如果一個類中提供了帶引數的構造方法,建議建立不帶引數的那個構造方法
b>、在使用 constructor-arg 時,可以使用 index 、type 、name 來確定為那個引數注入值
c>、對於 "簡單型別" 來說,使用 value 屬性即可注入相應值; 
        對於其他引用型別來說使用 ref 屬性引用容器中已經宣告的其他Bean的id

3、基於介面方式的注入( Spring 預設不支援 )




【 Bean 的建立方式 ( bean creation ) 】


1、使用構造方法建立 Bean 例項

     比如:
     
      使用無參構造:
     <bean id="date" class="java.util.Date" /> 
     
     使用帶引數的構造:
     <bean id="student" class="org.malajava.injection.Student" >
<constructor-arg name="name" value="郭襄" />
<constructor-arg name="id" value="1" />
<constructor-arg name="number" value="1003" />
<constructor-arg name="gender" value="女" />
<constructor-arg name="birthdate" ref="date" />
<constructor-arg name="married" value="false" />
</bean>

2、靜態工廠方法

public class Car {
private String brand ;
public static Car getInstance() {
System.out.println( "Car.getInstance()" );
Car c = new Car();
return c ;
}
}

<bean id="car" 
class="org.malajava.creation.Car"
factory-method="getInstance" 
p:brand="BYD" />

<bean id="calendar" 
class="java.util.Calendar"
factory-method="getInstance" />

3、例項工廠方法

public class Bus {
private String brand ;
}

public class BusFactory {
public Bus create() {
Bus b = new Bus();
b.setBrand( "比亞迪" );
return b ;
}
}

<bean id="busFactory" class="org.malajava.creation.BusFactory" />

<bean id="bus" class="org.malajava.creation.Bus" factory-bean="busFactory" factory-method="create" >
<property name="brand" value="比亞迪" />
</bean>

4、FactoryBean

a>、需要有一個類實現了 org.springframework.beans.factory.FactoryBean 介面(並實現其中的抽象方法)
 
並指定 該實現類所建立的 物件的型別 (在型別引數中指定)

public class ShipFactoryBean implements FactoryBean<Ship>{
@Override
public Ship getObject() throws Exception { // 負責建立 Ship 型別的物件
return null;
}
@Override
public Class<?> getObjectType() { // 返回 所建立物件的型別
return null;
}
}
 
b>、在 FactoryBean 實現類內部的 getObject 方法用來建立 <T> 型別的物件
 
<!-- 如果 class 所制定的 類 實現了 FactoryBean 介面,
       那麼 這個配置所建立的物件 是由 該 FactoryBean 實現類的 getObject 方法所返回的物件 -->
<bean id="ship" class="org.malajava.creation.ShipFactoryBean" />