【每天学点Spring】

【每天学点Spring】FactoryBean

2022-04-30  本文已影响0人  伊丽莎白2015

关于FactoryBean的介绍:
Factory-Bean,工厂-造出Bean,首先它是一个Spring重要的接口,有很多实现类如:ProxyFactoryBean,JndiObjectFactoryBean等。

1. FactoryBean方法

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:

@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的子类:

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

参考:
baeldung - How to use the Spring FactoryBean?

上一篇下一篇

猜你喜欢

热点阅读