1、Setter注入
<bean id="helloWorld" class="com.jdw.spring.beans.HelloWorld"> <property name="name" value="Spring"></property> </bean>
從這個最簡單的配置可以得出以下兩個結論:一、class屬性需要全類名進行配置,說了ioc容器是通過反射進行創建bean的;二、bean類必須有默認的構造函數;
這種通過property子元素進行屬性配置的方式是spring依賴注入的三大方式之一:setter注入。
2、構造器注入
<bean id="car" class="com.jdw.spring.beans.Car"> <constructor-arg value="audi" type="java.lang.String"></constructor-arg> <constructor-arg type="java.lang.String"> <!-- 對於包含特殊字符的屬性值,可以在value子節點使用CDATA --> <value><![CDATA[<shanghai>]]></value> </constructor-arg> <constructor-arg type="int"> <value>240</value> </constructor-arg> </bean>
構造器注入,言外之意,需要在bean之中配置構造器,可以不需要默認構造方法,但是必須保證構造器參數與配置文件中的參數數量和類型一致。
<bean id="car1" class="com.jdw.spring.beans.Car"> <constructor-arg value="audi" index="0" type="java.lang.String"></constructor-arg> <constructor-arg value="shanghai" index="1" type="java.lang.String"></constructor-arg> <constructor-arg value="200000" index="2" type="double"></constructor-arg> </bean>
對於有多個構造器的bean,可通過上述的index和type屬性進行配置,以區別重載的構造器。
3、工廠方法注入
工廠方法注入又分為靜態工廠方法注入和實例工廠方法注入
(1)靜態工廠方法注入
一個模擬的簡單靜態工廠如下,該靜態工廠提供了一個靜態方法getCar,調用該方法則返回一個Car實例,注意紅色注釋,如果配置文件中scope=singleton,采用靜態工廠方法注入獲得的bean是否為單例呢?
public class StaticCarFactory {
public static Map<String,Car> cars=new HashMap<>();
static{
cars.put("audi", new Car("audi",300000));
cars.put("bmw", new Car("bmw",200000));
cars.put("hongqi", new Car("hongqi",600000));
}
public static Car getCar(String name){
//return new Car("audi",300000);//如果這么寫,那么獲得的car實例還是單例的么?
return cars.get(name);
}
}
靜態工廠注入配置:
<bean id="car" class="com.jdw.spring.factory.StaticCarFactory" factory-method="getCar"> <constructor-arg value="audi"></constructor-arg> </bean>
說明:所謂靜態工廠方法注入,不過是通過一個靜態方法創建bean的實例,注意,在singelton情況下該靜態方法只會在ioc容器初始化bean時調用一次,即不管getBean("car")多少次,都是返回的同一個Car對象。而在prototype情況下,getBean("car")調用一次就會對應的調用一次靜態方法getCar。從這里可以更好的理解singleton和prototype的區別,前者會在ioc容器初始化時創建,后者則在用戶調用時再創建。
(2)實例工廠方法注入
實例工廠代碼:
public class InstanceCarFactory { private Map<String, Car> cars = null; public InstanceCarFactory() { cars = new HashMap<>(); cars.put("audi", new Car("audi", 30000)); cars.put("BMW", new Car("audi", 20000)); cars.put("HQ", new Car("audi", 50000)); } public Car getCar(String brand) { return cars.get(brand); } }
實例工廠的getCar為非靜態,這就導致,必須先實例化該工廠,即需要配置該工廠的bean。
<!-- 配置實例工廠 --> <bean id="carFactory" class="com.jdw.spring.factory.InstanceCarFactory"></bean> <!-- 通過實例工廠配置bean --> <bean id="car1" factory-bean="carFactory" factory-method="getCar"> <constructor-arg name="brand" value="audi"></constructor-arg> </bean>
學而不思則罔,通過Setter注入和構造器注入可以很方便快捷的配置bean,靜態工廠注入和實例工廠注入到底是為了那樣?難道只是為了支持下工廠模式?spring你別逗好么,咱自己不就相當於一個超級bean工廠么!那干嘛還弄給工廠方法注入呢?一定有其原因。
有一家手機賣場,只賣A、B、C三種手機,假設顧客只關心價格price和參數信息info,那么問題來了,一個顧客進入賣場,說:我要買A手機。手機賣場(IOC)需要初始化一個A的Bean。又一個顧客進入賣場,說:我要B手機。手機賣場也得初始化一個B的bean。同樣,也得初始化C的bean。三個手機還好些,IOC就建立三個bean,那么10種手機呢?每種手機的info需要特殊處理呢?比如手機參數信息要有一系列的運算統計信息呢?這樣看來IOC貌似不適合把每個bean都放在配置文件里,也不適合建立多個bean。
解決方案就是,建立一個手機bean,通過工廠注入(靜態工廠、實例工廠都可以),傳入手機類型名稱,獲得對應的手機,只是要把bean配置為prototype,這樣運行時就可以獲取各式各樣的手機了!
那靜態工廠和實例工廠兩種注入方式,除了配置的不同,在應用上有什么區別么?