Spring工廠方法(factory-bean)配置bean
在spring的世界中, 我們通常會利用bean config file 或者 annotation注解方式來配置bean.
在第一種利用bean config file(spring xml)方式中, 還包括如下三小類
-
反射模式
-
工廠方法模式(本文重點)
-
Factory Bean模式
其中反射模式最常見, 我們需要在bean 配置中指明我們需要的bean object的全類名。
例如:
<bean id="car1" class="com.home.factoryMethod.Car"> <property name="id" value="1"></property> <property name="name" value="Honda"></property> <property name="price" value="300000"></property> </bean>
上面bean 里面的class屬性就是全類名, Spring利用Java反射機制創建這個bean。
Factory方法模式
本文介紹的是另1種模式, 在工廠方法模式中, Spring不會直接利用反射機制創建bean對象, 而是會利用反射機制先找到Factory類,然后利用Factory再去生成bean對象。
而Factory Mothod方式也分兩種, 分別是靜態工廠方法 和 實例工廠方法。
靜態工廠方法方式
所謂靜態工廠方式就是指Factory類不本身不需要實例化, 這個Factory類中提供了1個靜態方法來生成bean對象
bean類Car
首先我們定義1個bean類Car
package com.home.factoryMethod;
public class Car {
private int id;
private String name;
private int price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "Car [id=" + id + ", name=" + name + ", price=" + price + "]";
}
public Car(){
}
public Car(int id, String name, int price) {
super();
this.id = id;
this.name = name;
this.price = price;
}
}
然后我們再定義1個工廠類CarStaticFactory
package com.home.factoryMethod;
import java.util.HashMap;
import java.util.Map;
public class CarStaticFactory {
private static Map<Integer, Car> map = new HashMap<Integer,Car>();
static{
map.put(1, new Car(1,"Honda",300000));
map.put(2, new Car(2,"Audi",440000));
map.put(3, new Car(3,"BMW",540000));
}
public static Car getCar(int id){
return map.get(id);
}
}
里面定義了1個靜態的bean 容器map. 然后提供1個靜態方法根據Car 的id 來獲取容器里的car對象。
xml配置
<bean id="bmwCar" class="com.home.factoryMethod.CarStaticFactory" factory-method="getCar">
<constructor-arg value="3"></constructor-arg>
</bean>
<bean id="audiCar" class="com.home.factoryMethod.CarStaticFactory" factory-method="getCar">
<constructor-arg value="2"></constructor-arg>
</bean>
可以見到, 利用靜態工廠方法定義的bean item種, class屬性不在是bean的全類名, 而是靜態工廠的全類名, 而且還需要指定工廠里的
getBean 靜態方法名字和參數
客戶端代碼
public static void h(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-factoryMethod.xml");
Car car1 = (Car) ctx.getBean("bmwCar");
System.out.println(car1);
car1 = (Car) ctx.getBean("audiCar");
System.out.println(car1);
}
小結
由上面的例子, 靜態工廠方法方式是非常適用於作為1個bean容器(集合的), 只不過吧bean集合定義在工廠類里面而不是bean config file里面。
缺點也比較明顯, 把數據寫在class里面而不是配置文件中違反了我們程序猿的常識和spring的初衷。當然優點就是令到令人惡心的bean config file更加簡潔啦。
實例工廠方法方式
所謂實例工廠方式也很容易看懂, 就是里面的getBean 方法不是靜態的, 也就是代表要先實例1個工廠對象, 才能依靠這個工廠對象去獲得bean 對象。
用回上面的例子。
而這次我們寫1個實例工廠類
CarInstanceFactroy
package com.home.factoryMethod;
import java.util.HashMap;
import java.util.Map;
public class CarInstanceFactory {
private Map<Integer, Car> map = new HashMap<Integer,Car>();
public void setMap(Map<Integer, Car> map) {
this.map = map;
}
public CarInstanceFactory(){
}
public Car getCar(int id){
return map.get(id);
}
}
bean xml寫法
<bean id="carFactory" class="com.home.factoryMethod.CarInstanceFactory">
<property name="map">
<map>
<entry key="4">
<bean class="com.home.factoryMethod.Car">
<property name="id" value="4"></property>
<property name="name" value="Honda"></property>
<property name="price" value="300000"></property>
</bean>
</entry>
<entry key="6">
<bean class="com.home.factoryMethod.Car">
<property name="id" value="6"></property>
<property name="name" value="ford"></property>
<property name="price" value="500000"></property>
</bean>
</entry>
</map>
</property>
</bean>
<bean id="car4" factory-bean="carFactory" factory-method="getCar">
<constructor-arg value="4"></constructor-arg>
</bean>
<bean id="car6" factory-bean="carFactory" factory-method="getCar">
<constructor-arg value="6"></constructor-arg>
</bean
因為實例工廠本身要實例化, 所以我們可以在xml中 指定它里面容器的data, 解決了上面提到的靜態工廠方法的缺點啦
client代碼
public static void h2(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-factoryMethod.xml");
Car car1 = (Car) ctx.getBean("car4");
System.out.println(car1);
car1 = (Car) ctx.getBean("car6");
System.out.println(car1);
}
小結
實例工廠方式使用起來更加靈活, FactoryBean比起工廠方法方式更加常見。

