工厂Bean

406 阅读2分钟

概述

在Spring容器中有一类特殊的bean叫工厂bean,普通的bean注入容器内的方式是通过调用其无参构造器创建一个对象导入在容器中,而工厂bean会通过FactoryBean的接口的getObject()方法将对象注册在容器中。

public interface FactoryBean<T> {
    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

FactoryBean有三个方法:

  • getObject() //返回需要注册的对象 ,如果为单例,该实例会放到Spring容器中单实例缓存池中
  • getObjectType() //返回对象的类型
  • isSingleton() //是否是单例 ,非单例时每次创建都会返回一个新的bean

实现原理简单案例

下面通过一个简单的小案例来说明:

  • 接口

public interface Person {
    public void speak();
} 
  • 实现类

public class Woman implements Person, BeanNameAware {

    private String beanName;

    @Override
    public void speak() {
        System.out.println("woman is talking");
    }

    @Override
    public void setBeanName(String beanName) {
        this.beanName = beanName;

    }
}
  • 工厂bean

public class PersonFactorybean implements FactoryBean<Person> {

    private Person person;

//    返回生产的对象
    @Override
    public Person getObject() throws Exception {
       person=new Woman();
        return person;
    }

    //返回生产的类型
    @Override
    public Class<?> getObjectType() {
        return Woman.class;
    }

//    返回是否时单例
    @Override
    public boolean isSingleton() {
        return false;
    }
}
  • 注解配置

@Configuration
public class BeanConfig {

    @Bean
    public PersonFactorybean factorybean() {
        return new PersonFactorybean();
    }
}
  • 测试输出

@RunWith(SpringRunner.class)
@SpringBootTest
public class FactorybeanApplicationTests {

    @Test
    public void contextLoads() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        Object bean = context.getBean("factorybean");
        System.out.println(bean);
    }

}

最后输出的是com.demo.factorybean.Woman@7f02251 对象。

应用场景

在某些场景下,实例化的过程比较复杂,需要大量的配置信息。如在Spring+MyBatis的环境下,我们配置一个SqlSessionFactoryBean来充当SqlSessionFactory,如下:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="mapperLocations" value="classpath:com/cn/mapper/*.xml"></property>
</bean>

在很多开源框架和spring集成的时候也用到FactoryBean,Spring为FactoryBean提供了70多个实现,比如Poxy、RMI等,足见其应用值广泛。