Spring 通过工厂方法(Factory Method)来配置bean

来源:互联网 发布:des算法 vb 编辑:程序博客网 时间:2024/04/28 07:09

在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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

上面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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

然后我们再定义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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

里面定义了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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

可以见到, 利用静态工厂方法定义的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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输出

May 30, 2016 11:17:45 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefreshINFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@43765ab3: startup date [Mon May 30 23:17:45 CST 2016]; root of context hierarchyMay 30, 2016 11:17:46 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitionsINFO: 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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

小结

由上面的例子, 静态工厂方法方式是非常适用于作为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);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

因为实例工厂本身要实例化, 所以我们可以在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);    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输出结果

May 31, 2016 12:22:28 AM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefreshINFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5d79a4c9: startup date [Tue May 31 00:22:28 CST 2016]; root of context hierarchyMay 31, 2016 12:22:28 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitionsINFO: 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]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

小结

本人觉得实例工厂方式使用起来更加灵活啦, 不过项目中其实本文一开始提到的第三种方法FactoryBean比起工厂方法方式更加常见。

0 0
原创粉丝点击