Spring IOC(四)FactoryBean

Spring IOC(四)FactoryBean

Spring 系列目錄(http://www.javashuo.com/article/p-kqecupyl-bm.html)html

SingletonBeanRegistry 類圖

通常狀況下,Spring 經過反射機制利用 bean 的 class 屬性指定實現類來實例化 bean。在某些狀況下特別是整合第三方包時,實例化 bean 過程比較複雜,若是按照傳統的方式,則須要在 XML 中提供大量的配置信息,配置方式的靈活性是受限的,這時採用編碼的方式可能會獲得一個簡單的方案。Spring 爲此提供了一個 FactoryBean 的工廠類接口,用戶能夠經過實現該接口定製實例化 bean 的邏輯。java

public interface FactoryBean<T> {
    T getObject() throws Exception;
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

在該接口中還定義瞭如下3個方法:spring

(1) T getObject():返回由 FactoryBean 建立的 bean 實例,若是 isSingleton() 返回 true,則該實例會放到 Spring 容器中單實例存池中緩存

(2) boolean isSingleton():返回由 FactoryBean 建立的 bean 實例的做用域是 singleton 仍是 prototypeide

(3) Class<?> getObjectType():返回 FactoryBean 建立的 bean 類型。post

1、Spring 中使用 FactoryBean

在以下的 Bean 經過 FactoryBean 注入this

public class CarFactoryBean implements FactoryBean<Car> {
    private String carInfo;

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

    @Override
    public Class<?> getObjectType() {
        return null;
    }
}

public class Car {
    private String brand;
    private int maxSpeed;
    private Double price;
    // get/set
}

有了這個 CarFactoryBean 後,就能夠在配置文件中使用下面這種自定義的配置方式配置了編碼

<bean id="car" class="spring.factory_bean.CarFactoryBean">
    <property name="carInfo" value="紅旗CA72,200,20000.00"/>
</bean>

當調用 getBean("car") 時,Spring 經過反射機制發現 CarFactoryBean 實現了 FactoryBean 的接口,這時 Spring 容器就調用接口方法 CarFactoryBean#getObject() 方法返回。若是但願獲取 CarFactoryBean 的實例,則須要在使用 getBean(beanName) 方法時在 beanName 前顯示的加上 & 前綴,例如 getBean("&car")prototype

2、FactoryBeanRegistrySupport

FactoryBeanRegistrySupport 提供了對 FactoryBean 的支持,最重要的方法是 getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess),這個方法經過 factoryBean 獲取 bean 對象。code

(1) 屬性

// 緩存 beanName -> FactoryBean 的集合
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);

(2) getObjectFromFactoryBean 註冊

getObjectFromFactoryBean 負責從 FactoryBean#getObject() 中獲取真正想要的 bean 對象,而不是 FactoryBean 自己。AbstractBeanFactory#getObjectForBeanInstance 獲取 bean 以前會判斷是否是 FactoryBean。

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    if (factory.isSingleton() && containsSingleton(beanName)) {
        synchronized (getSingletonMutex()) {
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                object = doGetObjectFromFactoryBean(factory, beanName);
                // Only post-process and store if not put there already during getObject() call above
                // (e.g. because of circular reference processing triggered by custom getBean calls)
                // TODO ? 什麼意思,循環引用?
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) {
                    object = alreadyThere;
                } else {
                    if (shouldPostProcess) {
                        if (isSingletonCurrentlyInCreation(beanName)) {
                            // Temporarily return non-post-processed object, not storing it yet..
                            return object;
                        }
                        beforeSingletonCreation(beanName);
                        try {
                            // 外面 BeanPostProcessor 做用在 factory 上,沒有做用在實際想要的實例上,這邊補一個
                            // 也就是說 BeanPostProcessor 的 postProcessBeforeInitialization 不會做用在 FactoryBean 上
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        } catch (Throwable ex) {
                            throw new BeanCreationException(beanName", ex);
                        } finally {
                            afterSingletonCreation(beanName);
                        }
                    }
                    if (containsSingleton(beanName)) {
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }
            }
            return object;
        }
    } else {
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (shouldPostProcess) {
            try {
                object = postProcessObjectFromFactoryBean(object, beanName);
            } catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        return object;
    }
}

// 調用 FactoryBean#getObject() 建立 bean
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
        throws BeanCreationException {
    Object object = factory.getObject();

    if (object == null) {
        if (isSingletonCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(
                    beanName, "FactoryBean which is currently in creation returned null from getObject");
        }
        object = new NullBean();
    }
    return object;
}

// 子類重寫
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {
    return object;
}

(3) 查找與刪除

protected Object getCachedObjectForFactoryBean(String beanName) {
    return this.factoryBeanObjectCache.get(beanName);
}

@Override
protected void removeSingleton(String beanName) {
    synchronized (getSingletonMutex()) {
        super.removeSingleton(beanName);
        this.factoryBeanObjectCache.remove(beanName);
    }
}
@Override
protected void clearSingletonCache() {
    synchronized (getSingletonMutex()) {
        super.clearSingletonCache();
        this.factoryBeanObjectCache.clear();
    }
}

(4) 其它方法

protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) {
    return factoryBean.getObjectType();
}

protected FactoryBean<?> getFactoryBean(String beanName, Object beanInstance) throws BeansException {
    if (!(beanInstance instanceof FactoryBean)) {
        throw new BeanCreationException(beanName,
                "Bean instance of type [" + beanInstance.getClass() + "] is not a FactoryBean");
    }
    return (FactoryBean<?>) beanInstance;
}

天天用心記錄一點點。內容也許不重要,但習慣很重要!

相關文章
相關標籤/搜索