Spring 中接口 FactoryBean 的使用

概述

Spring 中有两类bean:普通bean(ordinary bean)和工厂bean(factory bean)。要实现一个工厂bean,只要类实现接口 org.springframework.beans.factory.FactoryBean 即可1 2
FactoryBean 接口的定义如下:

public interface FactoryBean<T> {
    T getObject() throws Exception;
    Class<?> getObjectType();
    boolean isSingleton();
}

这是个泛型接口,泛型 T 指明了这个工厂bean产生的对象的类型。

使用方式

先定义一个普通的类,即工厂bean要产生的bean类型:

public class Tool {
    private int id;
    // standard constructors, getters and setters
}

再来一个实现 FactoryBean 接口的类:

public class ToolFactory implements FactoryBean<Tool> {
 
    private int factoryId;
    private int toolId;
 
    @Override
    public Tool getObject() throws Exception {
        return new Tool(toolId);
    }
 
    @Override
    public Class<?> getObjectType() {
        return Tool.class;
    }
 
    @Override
    public boolean isSingleton() {
        return false;
    }
 
    // standard setters and getters
}

接下来装配这个工厂类。

1. 基于XML的配置

用基于XML的配置来装配这个工厂bean:

<beans ...>
    <bean id="tool" class="com.baeldung.factorybean.ToolFactory">
        <property name="factoryId" value="9090"/>
        <property name="toolId" value="1"/>
    </bean>
</beans>

最后测试下,发现容器可以成功注入我们想要的Tool类的bean了:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:factorybean-spring-ctx.xml" })
public class FactoryBeanXmlConfigTest {
    @Autowired
    private Tool tool;
 
    @Test
    public void testConstructWorkerByXml() {
        assertThat(tool.getId(), equalTo(1));
    }
}

也就是说: 容器是用 FactoryBeangetObject() 方法产生的bean来进行依赖注入,而不是工厂 bean 本身

也可以直接使用工厂 bean,这需要在bean的名称前加&,如下所示:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:factorybean-spring-ctx.xml" })
public class FactoryBeanXmlConfigTest {
 
    @Resource(name = "&tool")
    private ToolFactory toolFactory;
 
    @Test
    public void testConstructWorkerByXml() {
        assertThat(toolFactory.getFactoryId(), equalTo(9090));
    }
}

2. 基于Java的配置

基于Java的配置来装配工厂 bean,与基于xml的有所不同。除了配置工厂 bean外,还需要配置 FactoryBeangetObject() 返回的bean,如下所示:

@Configuration
public class FactoryBeanAppConfig {

    @Bean(name = "tool")
    public ToolFactory toolFactory() {
        ToolFactory factory = new ToolFactory();
        factory.setFactoryId(7070);
        factory.setToolId(2);
        return factory;
    }
 
    @Bean
    public Tool tool() throws Exception {
        return toolFactory().getObject();
    }
}

然後测试下是否能够正确注入(注:在注入时,实际产生的bean,只用 @Autowired 注解即可;而工厂bean则仍需要在 @Resource 注解中通过 name 属性带上 & 来指明):

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = FactoryBeanAppConfig.class)
public class FactoryBeanJavaConfigTest {
 
    @Autowired
    private Tool tool;
  
    @Resource(name = "&tool")
    private ToolFactory toolFactory;
 
    @Test
    public void testConstructWorkerByJava() {
        assertThat(tool.getId(), equalTo(2));
        assertThat(toolFactory.getFactoryId(), equalTo(7070));
    }
}

测试结果会显示与前面基于XML的配置方式类似的效果。


  1. How to use the Spring FactoryBean? ↩︎

  2. 如何使用Spring FactoryBean? ↩︎

你可能感兴趣的:(转译,Spring)