工廠Bean

玉獅子發表於2019-04-23

概述

在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等,足見其應用值廣泛。

相關文章