【每天学点Spring】FactoryBean
关于FactoryBean的介绍:
Factory-Bean,工厂-造出Bean,首先它是一个Spring重要的接口,有很多实现类如:ProxyFactoryBean,JndiObjectFactoryBean等。
1. FactoryBean方法
- T getObject(): 返回FactoryBean创建的对象,创建的对象会被spring容器管理。
- Class<?> getObjectType(): 返回FactoryBean创建Bean的类型。
- default boolean isSingleton(): 定义getObject()创建的对象是否为单例。
2. 简单例子
2.1 实现FactoryBean接口:
@Data
@AllArgsConstructor
public class User {
private int id;
}
UserFactory类实现了FactoryBean接口,在getObject()里负责创建新的user对象:
@Data
public class UserFactory implements FactoryBean<User> {
private int factoryId;
private int userId;
@Override
public User getObject() throws Exception {
return new User(userId);
}
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
2.2 使用@Configuration配置bean:
定义了一个Bean,返回UserFactory。
这里比较我有意思的是,如果UserFactory是普通的bean,那么名称为user的bean就是UserFactory的实例。
但恰恰因为UserFactory不是普通的bean(它实现了FactoryBean接口),所以并不能像普通bean那样的用法,而是会调用getObject()方法,来创建出新的对象实例。
以下的@Configuration会创建出两个bean:
- bean, name = "user", 实例是user对象。
- bean,name="&user", 实例是userFactory对象。
@Configuration
public class FactoryBeanAppConfig {
@Bean(name = "user")
public UserFactory userFactory() {
UserFactory factory = new UserFactory();
factory.setFactoryId(1001);
factory.setUserId(1);
return factory;
}
}
测试类:
@SpringBootTest
public class FactoryBeanAppConfigTest {
@Autowired
private User user;
@Resource(name = "&user")
private UserFactory userFactory;
@Test
public void test() {
assertThat(user.getId(), equalTo(1));
assertThat(userFactory.getFactoryId(), equalTo(1001));
}
}
3. AbstractFactoryBean
Spring提供了AbstractFactoryBean抽象类,它是FactoryBean的一个实现,我们可以通过继承它更方便的创建出实例。
3.1 AbstractFactoryBean的singleton属性
AbstractFactoryBean类有个参数:singleton,默认为true,也就是默认通过getObject()创建出的对象都是单例的。如果设为false,则会调用createInstance()方法来创建实例(该方法是抽象方法,需要子类实现)。
以下是AbstractFactoryBean类getObject()方法源码(基于版本:spring-beans:5.3.13.jar),可以看出上述逻辑:
public final T getObject() throws Exception {
if (isSingleton()) {
return (this.initialized ? this.singletonInstance : getEarlySingletonInstance());
} else {
return createInstance();
}
}
3.2 AbstractFactoryBean例子
新建两个AbstractFactoryBean的子类:
- SingleToolFactory:继续了AbstractFactoryBean,默认singleton为true。
- NonSingleToolFactory:set singleton为false。
@Data
public class SingleUserFactory extends AbstractFactoryBean<User> {
private int factoryId;
private int userId;
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
protected User createInstance() throws Exception {
return new User(userId);
}
}
@Data
public class NonSingleUserFactory extends AbstractFactoryBean<User> {
private int factoryId;
private int userId;
public NonSingleUserFactory() {
setSingleton(false);
}
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
protected User createInstance() throws Exception {
return new User(userId);
}
}
用@Configuration配置bean:
@Configuration
public class AbstractFactoryBeanConfig {
@Bean(name = "singleUser")
public SingleUserFactory singleUserFactory() {
SingleUserFactory factory = new SingleUserFactory();
factory.setFactoryId(3001);
factory.setUserId(1);
return factory;
}
@Bean(name = "nonSingleUser")
public NonSingleUserFactory nonSingleUserFactory() {
NonSingleUserFactory factory = new NonSingleUserFactory();
factory.setFactoryId(3002);
factory.setUserId(2);
return factory;
}
}
测试,可以看出单例FactoryBean创建的两个user对象实例是一样的。
非单例的FactoryBean创建的两个user对象实例是不一样的。
@SpringBootTest
public class AbstractFactoryBeanTest {
@Resource(name = "singleUser")
private User user1;
@Resource(name = "singleUser")
private User user2;
@Resource(name = "nonSingleUser")
private User user3;
@Resource(name = "nonSingleUser")
private User user4;
@Test
public void testSingleUserFactory() {
assertThat(user1.getId(), equalTo(1));
assertTrue(user1 == user2);
}
@Test
public void testNonSingleUserFactory() {
assertThat(user3.getId(), equalTo(2));
assertThat(user4.getId(), equalTo(2));
assertTrue(user3 != user4);
}
}