1.关于FactoryBean
它是spring容器提供的一种可以扩展容器对象实例化逻辑的接口,同时,从它的名字也可以看出它本身也是一个Bean,与注册到容器的其他对象一样;
2.FactoryBean的使用
介绍就免了,spring源码一搜就有,这里我主要讲下它在spring和springboot中的使用。
首先,我们先定义一个对象,代码如下:
@Data
@AllArgsConstructor
public class Tool {
private int id;
}
然后,我们通过这个借助这个对象去扩展FactoryBean接口:
@Data
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;
}
}
然后,如果我们是使用的spring的xml格式配置的话,请这么玩:
<bean id="tool" class="com.tyust.spring.boot.demo.factory.ToolFactory">
<property name="factoryId" value="9090"/>
<property name="toolId" value="1"/>
</bean>
测试案例如下:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring-ctx.xml" })
public class SpringApplicationTest {
@Resource(name = "&tool")
private ToolFactory toolFactory;
@Autowired
private Tool tool;
@Test
public void test() {
assertThat(toolFactory.getFactoryId(), equalTo(9090));
assertThat(tool.getId(), equalTo(1));
}
}
如果使用的是springboot形式,以代码的形式配置的话,请用如下代码替换xml的配置:
@Configuration
public class AppConfig {
@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();
}
}
测试案例,可以依照如下方式注入:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = FactoryBeanAppConfig.class)
public class SpringApplicationTest {
@Autowired
private Tool tool;
@Resource(name = "&tool")
private ToolFactory toolFactory;
@Test
public void testConstructWorkerByJava() {
assertThat(tool.getId(), equalTo(2));
assertThat(toolFactory.getFactoryId(), equalTo(7070));
}
}
spring提供了一个AbstractFactoryBean作为一个简单的模版类用于扩展FactoryBean,通过这个类,我们可以方便的建一个Singleton或者prototype的类去使用;
singleton的方式:
@Data
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);
}
}
prototype的方式:
@Data
public class PrototypeToolFactory 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);
}
}
配置的话,提供一种,springboot的跟上面的类似,就不贴出来了.
<bean id="singletonTool" class="com.tyust.spring.boot.demo.factory.SingleToolFactory">
<property name="factoryId" value="3001"/>
<property name="toolId" value="1"/>
</bean>
<bean id="prototypeTool" class="com.tyust.spring.boot.demo.factory.NonSingleToolFactory">
<property name="factoryId" value="3002"/>
<property name="toolId" value="2"/>
</bean>
测试的代码如下:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring-ctx.xml" })
public class SpringApplicationTest {
@Resource(name = "singletonTool")
private Tool tool1;
@Resource(name = "singletonTool")
private Tool tool2;
@Resource(name = "prototypeTool")
private Tool tool3;
@Resource(name = "prototypeTool")
private Tool tool4;
@Test
public void testSingleToolFactory() {
assertThat(tool1.getId(), equalTo(1));
assertTrue(tool1 == tool2);
}
@Test
public void testPrototypeToolFactory() {
assertThat(tool3.getId(), equalTo(2));
assertThat(tool4.getId(), equalTo(2));
assertTrue(tool3 != tool4);
}
}
通过这篇文章,我简要的给大家讲述下了FactoryBean和AbstractFactoryBean的使用,spring用FactoryBean类型的bean定义,通过正常的id引用,返回的是FactoryBean所"生产"的对象类型m,而非Factory本身,而factoryBean本身可以通过在bean定义的id前面添加前缀&来获取.要了解更多FactoryBean的内容,读者可以看看spring内部实现的一些案例:
DateTimeFormatterFactoryBean,HessianProxyFactoryBean,LocalConnectionFactoryBean等等;