歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Spring 通過工廠方法(Factory Method)來配置bean

Spring 通過工廠方法(Factory Method)來配置bean

日期:2017/3/1 9:08:18   编辑:Linux編程

Spring 通過工廠方法(Factory Method)來配置bean

在spring的世界中, 我們通常會利用bean config file 或者 annotation注解方式來配置bean.

在第一種利用bean config file(spring xml)方式中, 還包括如下三小類

  1. 反射模式
  2. 工廠方法模式(本文重點)
  3. 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配置

  <!-- 
        Static Factory method:
        class: the class of Factory
        factory-method: method of get Bean Object
        constructor-arg: parameters of factory-method
     -->
    <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);
}

輸出

May 30, 2016 11:17:45 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@43765ab3: startup date [Mon May 30 23:17:45 CST 2016]; root of context hierarchy
May 30, 2016 11:17:46 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [bean-factoryMethod.xml]
Car [id=3, name=BMW, price=540000]
Car [id=2, name=Audi, price=440000]

小結

由上面的例子, 靜態工廠方法方式是非常適用於作為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寫法

<!-- Instance Factory Method:
         1.must create a bean for the Instance Factroy First
     -->
     <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>

     <!-- 2.use Factory bean to get bean objectr 
        factory-bean : the bean define above
        factory-method: method of get Bean Object
        constructor-arg: parameters of factory-method
     -->
     <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);
    }

輸出結果

May 31, 2016 12:22:28 AM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5d79a4c9: startup date [Tue May 31 00:22:28 CST 2016]; root of context hierarchy
May 31, 2016 12:22:28 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [bean-factoryMethod.xml]
Car [id=4, name=Honda, price=300000]
Car [id=6, name=ford, price=500000]

小結

本人覺得實例工廠方式使用起來更加靈活啦, 不過項目中其實本文一開始提到的第三種方法FactoryBean比起工廠方法方式更加常見。

Copyright © Linux教程網 All Rights Reserved