Spring源码(9)-FactoryBean


一、介绍

一般情况下,Spring通过反射机制利用<bean>的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean<T>的形式

FactoryBean 是一个接口,当在IOC容器中的Bean实现了 FactoryBean 后,不同于普通Bean的是:通过getBean(String BeanName)获取到的Bean对象并不是FactoryBean的实现类对象,而是这个实现类中的getObject()方法返回的对象。要想获取FactoryBean的实现类,就要getBean(&BeanName),在BeanName之前加上&。即容器中会有两个 Bean。

简单来说,就是 FactoryBean 可以实现复杂 Bean 的创建。

虽然 @Bean 也可以实现复杂 Bean 的创建,但是一些批量创建 Bean 的操作还是必须由 FactoryBean 实现

FactoryBean应该是配合BeanDefiniton和Scan注解达到批量生产某个指定包下的bean,而不用一个一个手动创建这些bean的目的

FactoryBean的好处是spring与第三方jar包集成时,便于使用ioc注入bean,比如Mybatis的SqlSessionFactoryBean。Spring整合Mybatis也是通过实现FactoryBean,然后批量将BeanDefiniton注册到spring中管理

个人理解,FactoryBean 是很古早的一个类了,和 xml 初始化配套的东西,在 xml 时代配置文件能做的工作有限,只能通过工厂类初始化复杂的 bean。但是现在 java configuration 时代 java 本身就已经逻辑完备了,只使用 @Bean 就可以满足复杂 bean 的初始化需求。所以现在看来 FactoryBean 可以算作一个历史遗留的备选方案吧

二、接口

由BeanFactory中使用的对象实现的接口,这些对象本身就是单个对象的工厂。如果一个bean实现了这个接口,那么它将被用作要公开的对象的工厂,而不是直接用作将自己公开的bean实例。

注意:实现此接口的bean不能作为普通bean使用。FactoryBean是以bean风格定义的,但是为bean引用公开的对象(getObject())始终是它所创建的对象。

FactoryBeans可以支持单例和原型,可以按需惰性地创建对象,也可以在启动时快速创建对象。SmartFactoryBean接口允许公开更细粒度的行为元数据。

这个接口在框架本身中被大量使用,例如AOP的org.springframework.aop.framework.ProxyFactoryBean或org.springframework.jndi.JndiObjectFactoryBean。它也可以用于定制组件;但是,这只在基础结构代码中常见。

FactoryBean是一个编程契约。实现不应该依赖于注释驱动的注入或其他反射工具。getObjectType() getObject()调用可能在引导过程的早期到达,甚至在任何后处理器设置之前。如果需要访问其他bean,则实现BeanFactoryAware并以编程方式获取它们。

最后,FactoryBean对象参与了包含BeanFactory的bean创建的同步。除了在FactoryBean本身(或类似)内进行惰性初始化之外,通常不需要内部同步。

public interface FactoryBean<T> {

    /**
    * 可以在beandefinition上设置的属性的名称,这样当不能从工厂bean类中推导出对象类型时,工厂bean就可以标识他的类型。
    */
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    /**
     * 返回这个工厂管理的对象的实例(可能是共享的,也可能是独立的)。
     * 与BeanFactory一样,这允许同时支持单例和原型设计模式。
     * 
     * 如果这个FactoryBean在调用时还没有完全初始化(例如,因为它涉及到循环引用中),
     * 则抛出相应的FactoryBeanNotInitializedException。
     * 
     * 从Spring 2.0开始,FactoryBeans允许返回空对象。
     * 工厂会将此视为正常值使用;在这种情况下,它将不再抛出FactoryBeanNotInitializedException。
     * 现在鼓励FactoryBean实现在适当的时候抛出FactoryBeanNotInitializedException。
     */
    @Nullable
    T getObject() throws Exception;

    /**
     * 返回这个FactoryBean创建的对象类型,如果事先不知道,则返回null。
     *
     * 这允许在不实例化对象的情况下检查特定类型的bean,例如在自动装配时。
     *
     * 在创建单例对象的实现中,该方法应该尽量避免创建单例对象;它应该提前估计类型。
     * 对于原型,在这里返回有意义的类型也是可取的。
     *
     * 这个方法可以在FactoryBean完全初始化之前调用。它不能依赖于初始化过程中创建的状态;
     * 当然,如果可用,它仍然可以使用这种状态。
     *
     * 注意:自动装配将简单地忽略这里返回null的FactoryBeans。
     * 因此,强烈建议使用FactoryBean的当前状态正确地实现此方法。
     */
    @Nullable
    Class<?> getObjectType();

    /**
     * 这个工厂管理的对象是单例对象吗?也就是说,getObject()是否总是返回相同的对象(可以缓存的引用)?
     *
     * 注意:如果FactoryBean指示保存一个单例对象,
     * 那么从getObject()返回的对象可能会被所属的BeanFactory缓存。
     * 因此,除非FactoryBean总是公开相同的引用,否则不要返回true。
     *
     * FactoryBean本身的单例状态通常由拥有它的BeanFactory提供;通常,它必须被定义为单例。
     *
     * 注意:此方法返回false并不一定表示返回的对象是独立的实例。
     * 扩展SmartFactoryBean接口的实现可以通过其SmartFactoryBean. 
     * isprototype()方法显式地指示独立实例。如果isSingleton()实现返回false,
     * 则不实现此扩展接口的普通FactoryBean实现被简单地假定总是返回独立实例。
     *
     * 默认实现返回true,因为FactoryBean通常管理一个单例实例。
     */
    default boolean isSingleton() {
        return true;
    }

}

三、基本使用

1、注解方式

@Component(value = "msgEntity")
public class TestFactoryBean implements FactoryBean<MsgEntity> {

    @Override
    public MsgEntity getObject() throws Exception {
        MsgEntity msgEntity = new MsgEntity();
        msgEntity.setId(1L);
        return msgEntity;
    }

    @Override
    public Class<?> getObjectType() {
        return MsgEntity.class;
    }
}

测试

@Autowired
private ApplicationContext applicationContext;

@Test
public void test13(){

    // 获取 FactoryBean 实现类
    Object mapperFactoryBean = applicationContext.getBean("&msgEntity");
    System.out.println(mapperFactoryBean);

    // 获取 FactoryBean 实现类 getObject() 方法产生的对象
    Object mapperFactoryBean2 = applicationContext.getBean("msgEntity");
    System.out.println(mapperFactoryBean2);

    Map<String, TestFactoryBean> beansOfType = applicationContext.getBeansOfType(TestFactoryBean.class);
    System.out.println(beansOfType);

    Map<String, MsgEntity> beansOfType2 = applicationContext.getBeansOfType(MsgEntity.class);
    System.out.println(beansOfType2);
}

输出

io.renren.modules.test.TestFactoryBean@758ac46
MsgEntity(id=1)
{&msgEntity=io.renren.modules.test.TestFactoryBean@758ac46}
{msgEntity=MsgEntity(id=1)}

2、Spring配置文件方式

<!-- 如果Class指定的类型是 实现了FactoryBean,那么通过id值获取到这个对象 -->
<bean id="msgEntity" class="com.rewind.factoryebean.TestFactoryBean" />

四、MapperFactoryBean

Mybatis 是通过 MapperFactoryBean 将 mapper 动态生成的代理类添加到工厂容器中

Spring框架启动时:

会扫描指定路径下的 Mapper 接口,将 Mapper 接口转换为 Spring 中的 BeanDefinition 对象,并且beanClass 属性为 MapperFactoryBeanSpring 框架在所有的 Bean 配置转换为 BeanDefinition 对象后,就会根据 BeanDefinition 对象的 beanClass 属性创建Bean的实例。

Spring框架启动后:

每个Mapper接口创建一个 MapperFactoryBean 对象,当我们通过Mapper接口获取Bean时,获取到的是 MapperFactoryBean 对象的 getObject() 方法返回的对象。

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
    private Class<T> mapperInterface;
    private boolean addToConfig = true;

    public MapperFactoryBean() {
    }

    public MapperFactoryBean(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    protected void checkDaoConfig() {
        super.checkDaoConfig();
        Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required");
        Configuration configuration = this.getSqlSession().getConfiguration();
        if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
            try {
                configuration.addMapper(this.mapperInterface);
            } catch (Exception var6) {
                this.logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", var6);
                throw new IllegalArgumentException(var6);
            } finally {
                ErrorContext.instance().reset();
            }
        }

    }

    public T getObject() throws Exception {
        return this.getSqlSession().getMapper(this.mapperInterface);
    }

    public Class<T> getObjectType() {
        return this.mapperInterface;
    }

    public boolean isSingleton() {
        return true;
    }

    public void setMapperInterface(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    public Class<T> getMapperInterface() {
        return this.mapperInterface;
    }

    public void setAddToConfig(boolean addToConfig) {
        this.addToConfig = addToConfig;
    }

    public boolean isAddToConfig() {
        return this.addToConfig;
    }
}

image-20230201143110567

image-20230201143902147


  目录