1. 程式人生 > >Spring源碼分析(十二)FactoryBean的使用

Spring源碼分析(十二)FactoryBean的使用

get cell int 創建 phone eof block 如果 cells

摘要:本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的源代碼。若有描述錯誤之處,歡迎指正。

一般情況下,Spring通過反射機制利用bean的class屬性指定實現類來實例化bean。在某些情況下,實例化bean過程比較復雜,如果按照傳統的方式,則需要在<bean>中提供大量 的配置信息,配置方式的靈活性是受限的,這時采用編碼的方式可能會得到一個簡單的方案。 Spring 為此提供了一個org.springframework.beans.factory.FactoryBean的工廠類接口,用戶可以通過實現該接口定制實例化bean的邏輯。

FactoryBean接口對於Spring框架來說占有重要的地位,Spring自身就提供了70多個 FactoryBean的實現。它們隱藏了實例化一些復雜bean的細節,給上層應用帶來了便利。從Spring 3.0開始,FactoryBean開始支持泛型,即接口聲明改為FactoryBean<T>的形式:

public interface FactoryBean<T> {

    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

在該接口中還定義了以下3個方法:

T getObject() 返回由 FactoryBean 創建的 bean 實例,如果 isSingleton()返回 true,則該實例會放到Spring容器中單實例緩存池中
Class<?> getObjectType() 返回 FactoryBean 創建的 bean 類型
boolean isSingleton() 返回由FactoryBean創建的bean實例的作用域是singleton還是 prototype。

當配置文件中<bean>的class屬性配置的實現類是FactoryBean時,通過getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的對象,相當於 FactoiyBean#getObject()代理了 getBean()方法。例如:如果使用傳統方式配置下面Car的<bean> 時,Car的每個屬性分別對應一個<property>元素標簽。

public class Car {
    private int maxSpeed; 
    private String brand; 
    private double price;
    // get/set 方法
)

如果用FactoryBean的方式實現就會靈活一些,下例通過逗號分割符的方式一次性地為Car 的所有屬性指定配置值:

public class CarFactoryBean implements FactoryBean<Car> {

    private String carInfo;

    @Nullable
    @Override
    public Car getObject() throws Exception {
        Car car = new Car();
        String[] infos = carInfo.split(",");
        car.setBrand(infos[0]);
        car.setMaxSpeed(Integer.valueOf(infos[1]));
        car.setPrice(Double.valueOf(infos[2]));
        return car;
    }

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

    @Override
    public boolean isSingleton() {
        return false;
    }

    // 接受逗號分隔符設置屬性信息
    public void setCarInfo(String carInfo) {
        this.carInfo = carInfo;
    }
}

有了這個CarFactoryBean後,就可以在配置文件中使用下面這種自定義的配置方式配置 Car Bean 了:

<bean id="car" class="org.cellphone.uc.CarFactoryBean" carInfo="超級跑車,400,2000000"/>

與調用 getBean("car")時, Spring 通過反射機制發現 CarFactoryBean 實現了 FactoryBean 的接口,這時Spring容器就調用接口方法CarFactoryBean#getObject()方法返回。如果希望獲取 CarFactoryBean的實例,則需要在使用getBean(beanName)方法時在beanName前顯示的加上 "&"前綴,例如 getBean(”&car")。

Spring源碼分析(十二)FactoryBean的使用