Spring中BeanFactory與FactoryBean的區別

在Spring中有BeanFactory和FactoryBean這2個接口,從名字來看很類似,比較容易搞混。html

1、BeanFactory

BeanFactory是一個接口,它是Spring中工廠的頂層規範,是SpringIoc容器的核心接口,它定義了getBean()containsBean()等管理Bean的通用方法。Spring的容器都是它的具體實現如:java

  • DefaultListableBeanFactoryspring

  • XmlBeanFactory設計模式

  • ApplicationContext安全

這些實現類又從不一樣的維度分別有不一樣的擴展。ide

1.一、源碼

public interface BeanFactory {

	//對FactoryBean的轉義定義,由於若是使用bean的名字檢索FactoryBean獲得的對象是工廠生成的對象,
	//若是須要獲得工廠自己,須要轉義
	String FACTORY_BEAN_PREFIX = "&";

	//根據bean的名字,獲取在IOC容器中獲得bean實例
	Object getBean(String name) throws BeansException;

	//根據bean的名字和Class類型來獲得bean實例,增長了類型安全驗證機制。
	<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;

	Object getBean(String name, Object... args) throws BeansException;

	<T> T getBean(Class<T> requiredType) throws BeansException;

	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	//提供對bean的檢索,看看是否在IOC容器有這個名字的bean
	boolean containsBean(String name);

	//根據bean名字獲得bean實例,並同時判斷這個bean是否是單例
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	//獲得bean實例的Class類型
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	//獲得bean的別名,若是根據別名檢索,那麼其原名也會被檢索出來
	String[] getAliases(String name);
}
複製代碼

1.一、使用場景

  • 從Ioc容器中獲取Bean(byName or byType)
  • 檢索Ioc容器中是否包含指定的Bean
  • 判斷Bean是否爲單例

2、FactoryBean

首先它是一個Bean,但又不只僅是一個Bean。它是一個能生產或修飾對象生成的工廠Bean,相似於設計模式中的工廠模式和裝飾器模式。它能在須要的時候生產一個對象,且不只僅限於它自身,它能返回任何Bean的實例。測試

2.一、源碼

public interface FactoryBean<T> {

	//從工廠中獲取bean
	@Nullable
	T getObject() throws Exception;

	//獲取Bean工廠建立的對象的類型
	@Nullable
	Class<?> getObjectType();

	//Bean工廠建立的對象是不是單例模式
	default boolean isSingleton() {
		return true;
	}
}
複製代碼

從它定義的接口能夠看出,FactoryBean表現的是一個工廠的職責。 即一個Bean A若是實現了FactoryBean接口,那麼A就變成了一個工廠,根據A的名稱獲取到的其實是工廠調用getObject()返回的對象,而不是A自己,若是要獲取工廠A自身的實例,那麼須要在名稱前面加上'&'符號。ui

  • getObject('name')返回工廠中的實例
  • getObject('&name')返回工廠自己的實例

一般狀況下,bean 無須本身實現工廠模式,Spring 容器擔任了工廠的 角色;但少數狀況下,容器中的 bean 自己就是工廠,做用是產生其餘 bean 實例。由工廠 bean 產生的其餘 bean 實例,再也不由 Spring 容器產生,所以與普通 bean 的配置不一樣,再也不須要提供 class 元素。this

2.二、示例

先定義一個Bean實現FactoryBean接口spa

@Component
public class MyBean implements FactoryBean {
    private String message;
    public MyBean() {
        this.message = "經過構造方法初始化實例";
    }
    @Override
    public Object getObject() throws Exception {
        // 這裏並不必定要返回MyBean自身的實例,能夠是其餘任何對象的實例。
        //如return new Student()...
        return new MyBean("經過FactoryBean.getObject()建立實例");
    }
    @Override
    public Class<?> getObjectType() {
        return MyBean.class;
    }
    public String getMessage() {
        return message;
    }
}
複製代碼

MyBean實現了FactoryBean接口的兩個方法,getObject()是能夠返回任何對象的實例的,這裏測試就返回MyBean自身實例,且返回前給message字段賦值。同時在構造方法中也爲message賦值。而後測試代碼中先經過名稱獲取Bean實例,打印message的內容,再經過&+名稱獲取實例並打印message內容。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class FactoryBeanTest {
    @Autowired
    private ApplicationContext context;
    @Test
    public void test() {
        MyBean myBean1 = (MyBean) context.getBean("myBean");
        System.out.println("myBean1 = " + myBean1.getMessage());
        MyBean myBean2 = (MyBean) context.getBean("&myBean");
        System.out.println("myBean2 = " + myBean2.getMessage());
        System.out.println("myBean1.equals(myBean2) = " + myBean1.equals(myBean2));
    }
}
複製代碼
myBean1 = 經過FactoryBean.getObject()初始化實例
myBean2 = 經過構造方法初始化實例
myBean1.equals(myBean2) = false
複製代碼

2.三、使用場景

說了這麼多,爲何要有FactoryBean這個東西呢,有什麼具體的做用嗎?
FactoryBean在Spring中最爲典型的一個應用就是用來建立AOP的代理對象

咱們知道AOP其實是Spring在運行時建立了一個代理對象,也就是說這個對象,是咱們在運行時建立的,而不是一開始就定義好的,這很符合工廠方法模式。更形象地說,AOP代理對象經過Java的反射機制,在運行時建立了一個代理對象,在代理對象的目標方法中根據業務要求織入了相應的方法。這個對象在Spring中就是——ProxyFactoryBean

因此,FactoryBean爲咱們實例化Bean提供了一個更爲靈活的方式,咱們能夠經過FactoryBean建立出更爲複雜的Bean實例。

3、區別

  • 他們兩個都是個工廠,但FactoryBean本質上仍是一個Bean,也歸BeanFactory管理
  • BeanFactory是Spring容器的頂層接口,FactoryBean更相似於用戶自定義的工廠接口。

總結

BeanFactoryFactoryBean的區別確實容易混淆,死記硬背是不行的,最好仍是從源碼層面,置於spring的環境中去理解。

參考:
www.cnblogs.com/yulinfeng/p…
www.cnblogs.com/guitu18/p/1…

相關文章
相關標籤/搜索