Skip to main content
 首页 » 编程设计

Spring FactoryBean实战教程

2022年07月19日130telwanggs

Spring Bean容器中有两者类型bean:普通bean和工厂bean。前者Spring直接使用,而后者能产生被框架管理的对象。我们可以实现org.springframework.beans.factory.FactoryBean 接口构建工厂bean。

1. 基本工厂bean

2.1 实现FactoryBean

首先看FactoryBean接口定义:

public interface FactoryBean { 
    T getObject() throws Exception; 
    Class<?> getObjectType(); 
    boolean isSingleton(); 
} 
  • getObject() – 返回工厂创建的对象,可以被Spring容器使用的对象。
  • getObjectType() – 返回工厂创建对象的类型
  • isSingleton() – 返回工厂创建对象是否为单例对象

现在实现一个示例,创建ToolFactory类负责创建Tool类型对象:

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

ToolFactory类:

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 
} 

ToolFactory 实现了 FactoryBean接口,负责创建Tool对象。

1.2 基于Java Configuration使用FactoryBean

当然也可以基于xml,这里使用java 方式配置,需要显示调用getObject()方法。

@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(); 
    } 
} 

然后,我们测试Tool对象注入是否正确:

@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)); 
    } 
} 

为了访问FactoryBean,需要在bean名称前面增加&符号。

有时需要在FactoryBean创建之后、getObject方法执行之前执行一些属性操作,如属性检查。可以实现InitializingBean 接口或使用 @PostConstruct 注解.

2. 抽象工厂bean

Spring还提供了AbstractFactoryBean,作为FactoryBean实现的简单模板超类。使用这个基类可以更方便实现工厂bean,创建单例或原型对象。
下面示例展示如何使用AbstractFactoryBean创建单例或原型对象。

public class SingleToolFactory extends AbstractFactoryBean<Tool> { 
 
    private int factoryId; 
    private int toolId; 
 
    @Override 
    public Class<?> getObjectType() { 
        return Tool.class; 
    } 
 
    @Override 
    protected Tool createInstance() throws Exception { 
        return new Tool(toolId); 
    } 
 
    // standard setters and getters 
} 

AbstractFactoryBean默认singleton属性为true,即单例方式。

下面创建非单例工厂类:

public class NonSingleToolFactory extends AbstractFactoryBean<Tool> { 
 
    private int factoryId; 
    private int toolId; 
 
    public NonSingleToolFactory() { 
        setSingleton(false); 
    } 
 
    @Override 
    public Class<?> getObjectType() { 
        return Tool.class; 
    } 
 
    @Override 
    protected Tool createInstance() throws Exception { 
        return new Tool(toolId); 
    } 
 
    // standard setters and getters 
} 

配置工厂bean,Java方式于上面一致,这里使用xml方式:

<beans ...> 
 
    <bean id="singleTool" class="com.baeldung.factorybean.SingleToolFactory"> 
        <property name="factoryId" value="3001"/> 
        <property name="toolId" value="1"/> 
    </bean> 
 
    <bean id="nonSingleTool" class="com.baeldung.factorybean.NonSingleToolFactory"> 
        <property name="factoryId" value="3002"/> 
        <property name="toolId" value="2"/> 
    </bean> 
</beans> 

现在测试被注入的对象是否于期望一致:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:factorybean-abstract-spring-ctx.xml" }) 
public class AbstractFactoryBeanTest { 
 
    @Resource(name = "singleTool") 
    private Tool tool1; 
  
    @Resource(name = "singleTool") 
    private Tool tool2; 
  
    @Resource(name = "nonSingleTool") 
    private Tool tool3; 
  
    @Resource(name = "nonSingleTool") 
    private Tool tool4; 
 
    @Test 
    public void testSingleToolFactory() { 
        assertThat(tool1.getId(), equalTo(1)); 
        assertTrue(tool1 == tool2); 
    } 
 
    @Test 
    public void testNonSingleToolFactory() { 
        assertThat(tool3.getId(), equalTo(2)); 
        assertThat(tool4.getId(), equalTo(2)); 
        assertTrue(tool3 != tool4); 
    } 
} 

从上面测试结果看,SingleToolFactory 产生单例对象, NonSingleToolFactory 产生原型对象.

3. 总结

使用FactoryBean封装复杂的构造逻辑非常方便。本文介绍了如何实现并配置FactoryBean,包括FactoryBean 和 AbstractFactoryBean。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/115361419