輕鬆實現 BeanFactory

BeanFactory 是字面意思是“Bean 工廠”,那麼顧名思義“Bean 工廠”就是用來生產 Bean 或者是用來存放 Bean 的嗎?
實際上 BeanFactory 是一個 Spring IoC 容器
那這個“Bean 工廠”是如何實現的呢?

BeanFactory 接口

這是一個最簡單的容器,它主要的功能是爲依賴注入 (DI) 提供支持,這個容器接口在 org.springframework.beans.factory.BeanFactor 中被定義。
我們實際使用的 “Bean 工廠” 都是 BeanFactory 接口的實現類,例如:

  • XmlBeanFactory(用來讀取配置文件)
  • StaticListableBeanFactory
  • DefaultListableBeanFactory
//利用 ClassPathResource() 去加載在路徑 CLASSPATH 下可用的 bean 配置文件
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring.xml"));

BeanFactory 代碼實現

看完概念可能還是有點懵,不要着急再往下看看。

Animal.java(接口)

public interface Animal {
    void eat();
}

Cat.java(實現Animal接口)

public class Cat implements Animal {
    public void eat() {
        System.out.println("貓喫魚");
    }
}

BeanFactory.java(“Bean 工廠”)

import java.util.HashMap;
import java.util.Map;

public class BeanFactory {

    private Map<String, Object> beans = new HashMap<>();

    public void addBeans(String id, Object bean) {
        beans.put(id, bean);
    }
    public Object getBeans(String id) {
        return beans.get(id);
    }
}

BeanUtils.java(工具類封裝 BeanFactory )

public class BeanUtils {

    //靜態變量
    private static BeanFactory beanFactory =new BeanFactory();

    //靜態塊 只執行一次
    //使用靜態塊實現了 BeanFactory(Spring IoC 容器)在創建的時候就實例化了Bean,而不是在 getBean 時才實例化Bean
    static {
        beanFactory.addBeans("Animal",new Cat());
    }

    //靜態方法(類調用)
    public static Object getBean(String id) {
        return beanFactory.getBeans(id);
    }
}

Tips:這裏爲什麼要創建BeanUtils來封裝BeanFactory 呢?因爲BeanFactory 是一個 Spring IoC 容器,在 Spring 中容器將創建對象並進行配置管理,而不是我們主動的去 new 一個對象,也是爲依賴注入 (DI) 提供支持。

MainTest.java(測試)

public class MainTest {

    public static void main(String[] args) {
    	//使用BeanUtils直接調用靜態方法getBean就獲取了Bean
        Animal animal = (Animal) BeanUtils.getBean("Animal");
        animal.eat();
    }
}

在這裏插入圖片描述
以上就是對 BeanFactory ( Spring IoC 容器)的簡單實現,可以將BeanFactory 理解爲一個存放和管理 Bean 的集合(至於 Spring 底層源碼使用的是什麼集合我不確定,但是肯定比這個簡單實現要複雜很多)。

FactoryBean 接口

說完了 BeanFactory,那麼疑問又來啦,FactoryBean 又是什麼呢?
簡單的說,BeanFactory 是 Factory 結尾是工廠;FactoryBean 是Bean 結尾是 Bean實例,但是這個Bean 實現了 FactoryBean 接口。

Bean 分類

Spring 中 Bean分爲兩種,具體如下:
1. 普通的Bean: < bean id="xxx" class="xxx"> ,Spring 直接創建 Bean 實例
2. FactoryBean: FactoryBean 是接口,爲IOC容器中Bean的實現提供了更加靈活的方式;是一個特殊的bean,具有工廠生成對象的能力,只能生成特定的對象。Bean必須實現 FactoryBean接口,此接口提供方法 getObject() 用於獲得特定bean。

FactoryBean(源碼)

public interface FactoryBean<T> {
	
	// 屬性名
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

	// 獲取bean實例,實例化bean 的邏輯就在這裏實現
	@Nullable
	T getObject() throws Exception;
	// 獲取bean類型
	@Nullable
	Class<?> getObjectType();
	// 是否是單例
	default boolean isSingleton() {
		return true;
	}
}
  • getObject() 返回 FactoryBean 管理的Bean 實例,並不是FactoryBean 本身的實例。
  • FactoryBean 管理的對象可以是 singleton (單例)也可以是prototype (非單例),所以此接口有了方法 isSingleton() 返回由FactoryBean 創建的Bean 實例的作用域是singleton還是prototype。
  • getObjectType() 最主要的目的就是在不創建實例的情況下就能知道想要創建的Bean 實例的類型。

Tips:從Spring3.0開始,FactoryBean開始支持泛型,即接口聲明改爲FactoryBean<T>的形式。

FactoryBean 與普通的 Bean 區別

FactoryBean不同於普通Bean的是:它是實現了FactoryBean<T>接口Bean,根據該Bean的IDBeanFactory中獲取的實際上是 FactoryBean的getObject()返回的特定 Bean 實例,而不是FactoryBean 本身,如果要獲取FactoryBean對象,需要在Bean id 前加一個 & 符號來獲取。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章