Spring系列十:Spring FactoryBean

3,021 阅读2分钟

重叠泪痕缄锦字,人生只有情难死。

概述

工厂bean是用作在IoC容器中创建其他bean的工厂,但它是特定的Spring的bean。从概念上讲,工厂bean非常类似于工厂方法,可以在bean构造期间由Spring IoC容器标识,并且可以由容器用来实例化其他bean

使用FactoryBean创建bean

要创建工厂bean,你只需要把创建的bean类实现FactoryBean接口,该类将创建实际所需要的bean。简单起见,您可以扩展AbstractFactoryBean类。

通过扩展AbstractFactoryBean类,工厂Bean可以简单地重写createInstance()方法来创建目标Bean实例。此外,你必须在getObjectType()方法中返回目标bean的类型,spring的自动装配功能才能正常工作。

public class EmployeeFactoryBean extends AbstractFactoryBean<Object>
{
    /This method will be called by container to create new instances
    @Override
    protected Object createInstance() throws Exception
    {
        //code
    }
 
    //This method is required for autowiring to work correctly
    @Override
    public Class<EmployeeDTO> getObjectType() {
        return EmployeeDTO.class;
    }
}

为什么使用工厂bean

工厂bean主要用于实现框架某些特定功能。如下:

  1. JNDI查找对象(例如数据源)时,可以使用JndiObjectFactoryBean
  2. 使用经典的Spring AOPbean创建代理时,可以使用ProxyFactoryBean
  3. IoC容器中创建Hibernate会话工厂时,可以使用LocalSessionFactoryBean

在大多数情况下,你几乎不必编写任何自定义工厂bean,因为它们框架的特定功能的,并且不能在Spring IoC容器范围之外使用。

FactoryBean 测试

在这个例子中,我正在创建一个工厂bean来实例化不同类型的Employee对象,例如他们的manager, director等具有一些预先填充的属性。

EmployeeDTO代码如下:

package cn.howtodoinjava.demo.model;
 
public class EmployeeDTO {
 
    private Integer id;
    private String firstName;
    private String lastName;
    private String designation;
 
    //Setters and Getters are hidden behind this comment.
 
    @Override
    public String toString() {
        return "Employee [id=" + id + ", firstName=" + firstName
                + ", lastName=" + lastName + ", type=" + designation + "]";
    }
}

EmployeeFactoryBean类继承了AbstractFactoryBean类,并实现了两个方法createInstance()getObjectType()

import org.springframework.beans.factory.config.AbstractFactoryBean;
 
import cn.howtodoinjava.demo.model.EmployeeDTO;
 
public class EmployeeFactoryBean extends AbstractFactoryBean<Object>
{
    private String designation;
     
    public String getDesignation() {
        return designation;
    }
 
    public void setDesignation(String designation) {
        this.designation = designation;
    }
 
    //This method will be called by container to create new instances
    @Override
    protected Object createInstance() throws Exception
    {
        EmployeeDTO employee = new EmployeeDTO();
        employee.setId(-1);
        employee.setFirstName("dummy");
        employee.setLastName("dummy");
        //Set designation here
        employee.setDesignation(designation);
        return employee;
    }
 
    //This method is required for autowiring to work correctly
    @Override
    public Class<EmployeeDTO> getObjectType() {
        return EmployeeDTO.class;
    }
}

在配置文件中定义各种Employee类型,如下所示。

<bean id="manager"  class="cn.howtodoinjava.demo.factory.EmployeeFactoryBean">
    <property name="designation" value="Manager" />
</bean>
 
<bean id="director"  class="cn.howtodoinjava.demo.factory.EmployeeFactoryBean">
    <property name="designation" value="Director" />
</bean>

测试工厂bean

public class TestSpringContext
{
    @SuppressWarnings("resource")
    public static void main(String[] args)
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
 
        EmployeeDTO manager = (EmployeeDTO) context.getBean("manager");
        System.out.println(manager);
         
        EmployeeDTO director = (EmployeeDTO) context.getBean("director");
        System.out.println(director);
    }
}

输出:

Employee [id=-1, firstName=dummy, lastName=dummy, type=Manager]
Employee [id=-1, firstName=dummy, lastName=dummy, type=Director]

如你所见,EmployeeFactoryBean使用相同的工厂方法创建了两个不同的员工对象。

获取FactoryBean实例本身

如果要获取EmployeeFactoryBean本身的实例,则可以在bean名称之前添加

EmployeeFactoryBean factory = (EmployeeFactoryBean) context.getBean("&director");
 
System.out.println(factory.getDesignation());
System.out.println(factory.getObjectType());
System.out.println(factory.getObject());

输出:

Director
 
class cn.howtodoinjava.demo.model.EmployeeDTO
 
Employee [id=-1, firstName=dummy, lastName=dummy, type=Director]

原文链接:Spring FactoryBean Example