I. Bean 的装配方式

在之前的教程中,我们都是通过在 application_context.xml 配置文件中 bean 的结点里的 class 属性来配置 Bean 的全类名,底层是通过反射的机制来装配 Bean 的。还有一种方法是通过工厂方法来进行 Bean 的装配,主要有三种:

  • 静态工厂方法
  • 实例工厂方法
  • Spring Factory Bean

II. 通过调用静态工厂方法创建 Bean

  • 调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中. 当客户端需要对象时, 只需要简单地调用静态方法, 而不同关心创建对象的细节.
  • 在配置文件中要配置通过静态工厂方法来创建的 Bean
    • 需要在 Bean 的 class 属性里指定拥有该工厂的方法的类
    • 同时在 factory-method 属性里指定工厂方法的名称
    • 最后, 使用 <constrctor-arg> 元素为该方法传递方法参数

下面来看一个代码示例,首先先创建一个类 Car, 拥有构造函数,setter/getter 和 toString 方法,然后创建一个静态工厂类 StaticCarFactory, 如下所示:

import java.util.Map;

/**
 * Author: PENG Zhengshuai
 * Date: 4/17/18
 * lovian.org
 */
public class StaticCarFactory {
    private static Map<String, Car> maps = new HashMap<String, Car>();

    static {
        maps.put("AUDI", new Car("Audi", "A6L", 50000));
        maps.put("BMW", new Car("BMW", "525L", 40000));
    }

    public static Car getCar(String name){
        return maps.get(name);
    }
}

然后我们新建一个配置文件 factory_beans.xml, 来配置 bean 实例

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- Here to config a Car instance, not a StaticCarFactory instance -->
    <bean id="audi" class="org.lovian.spring.bean.factory.StaticCarFactory" factory-method="getCar">
        <constructor-arg value="AUDI"/>
    </bean>
</beans>

注意,这里 class 属性中设置的 StaticCarFactory, 而不是 Car, 但这个 bean 并不是工厂方法的实例,而是 Car 的实例,然后指定 factory-method, 通过 constructor-argfactory-method 所需要的参数传进去

然后我们创建一个 main 函数来测试

package org.lovian.spring.demo;

import org.lovian.spring.bean.factory.Car;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Author: PENG Zhengshuai
 * Date: 4/17/18
 * lovian.org
 */
public class FactoryDemo {
    public static void main(String[] args) {
        ApplicationContext acxt = new ClassPathXmlApplicationContext("config/factory_beans.xml");
        Car car = (Car)acxt.getBean("audi");
        System.out.println(car.toString());
    }
}

结果如下:

Car{brand='Audi', model='A6L', price='50000', maxSpeed='0.0'}

III. 通过调用实例工厂方法创建 Bean

  • 实例工厂方法: 将对象的创建过程封装到另外一个对象实例的方法里. 当客户端需要请求对象时, 只需要简单的调用该实例方法而不需要关心对象的创建细节.
  • 要声明通过实例工厂方法创建的 Bean
    • 首先创建实例工厂的 factory bean
    • 在要创建的 bean 的 factory-bean 属性里指定拥有该工厂方法的 Bean
    • factory-method 属性里指定该工厂方法的名称
    • 使用 construtor-arg 元素为工厂方法传递方法参数

下面来看实例, 首先创建一个 InstanceCarFactory 类:

package org.lovian.spring.bean.factory;

import java.util.HashMap;
import java.util.Map;

/**
 * Author: PENG Zhengshuai
 * Date: 4/17/18
 * lovian.org
 */
public class InstanceCarFactory {
    private Map<String, Car> map;

    public InstanceCarFactory() {
        this.map = new HashMap<String, Car>();
        map.put("AUDI", new Car("Audi", "A6L", 50000));
        map.put("BMW", new Car("BMW", "525L", 40000));
    }

    public Car getCar(String name) {
        return this.map.get(name);
    }
}

然后再 factory_beans.xml 中配置 factory bean 和 car bean


    <bean id="carFactory" class="org.lovian.spring.bean.factory.InstanceCarFactory"/>

    <bean id="bmw"  factory-bean="carFactory" factory-method="getCar">
        <constructor-arg value="BMW"/>
    </bean>

执行 main 方法然后看结果

Car{brand='BMW', model='525L', price='40000', maxSpeed='0.0'}

可以看到,在配置了工厂方法以后,不需要声明 Car bean 的 class 属性,只需要设置好 factory-bean, factory-methodfactory-method 所需要的参数即可。也就是说,在有了工厂方法以后,就不需要去关注 car 类的所有细节,只需要知道工厂方法和其所需属性即可

III. 通过 Spring Factory Bean 来创建 Bean

FactoryBean 是 Spring 本身提供的一个接口,里面包含了三个方法:

  • getObject()
  • getObjectType()
  • isSingleton()

在使用 Spring FactoryBean的时候,需要实现 FactoryBean 接口。

下面用示例说明,先创建一个 CarFactoryBean:

package org.lovian.spring.bean.factory;

import org.springframework.beans.factory.FactoryBean;

/**
 * Author: PENG Zhengshuai
 * Date: 4/17/18
 * lovian.org
 */
public class CarFactoryBean implements FactoryBean<Car> {

    private String brand;
    private String model;
    private int price;

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public Car getObject() throws Exception {
        return new Car(brand, model, price);
    }

    public Class<?> getObjectType() {
        return Car.class;
    }

    public boolean isSingleton() {
        return true;
    }
}

然后在 xml 中配置这个 FactoryBean

<bean id="car" class="org.lovian.spring.bean.factory.CarFactoryBean">
        <property name="brand" value="AUDI"/>
        <property name="model" value="A6L"/>
        <property name="price" value="40000"/>
    </bean>

然后执行 main 方法,结果如下

Car{brand='AUDI', model='A6L', price='40000', maxSpeed='0.0'}

Share this on