使用FactoryBean介面實現自定義bean初始化
使用FactoryBean介面實現自定義bean初始化
本文所要介紹的FactoryBean是Spring中定義的一個介面,當把它的實現類定義為BeanFactory中的一個bean,我們在獲取其對應的bean時實際上獲取的是FactoryBean所包含的那個物件,而不是它本身。我們先來看一下FactoryBean的定義。
public interface FactoryBean<T> { /** * 獲取實際要返回的bean物件。 * @return * @throws Exception */ T getObject() throws Exception; /** * 獲取返回的物件型別 * @return */ Class<?> getObjectType(); /** * 是否單例 * @return */ boolean isSingleton(); }
我們可以看到FactoryBean是使用了泛型的,表示其對應產生的Bean是什麼型別的物件。我們來看一個實現。
public class UserFactoryBean implements FactoryBean<User> { private User user; @Override public User getObject() throws Exception { if (user == null) { synchronized (this) { if (user == null) { User user = new User(); user.setId(1); user.setName("張三"); this.user = user; } } } returnuser; } @Override public Class<?> getObjectType() { return User.class; } @Override public boolean isSingleton() { return true; } }
上面程式碼中定義了一個UserFactoryBean,用以產生一個單例的User物件。可以看到,我們在getObject()方法中使用了同步塊來保證產生的bean永遠是同一個物件。其實這個並不是必須的。在初始化時BeanFactory呼叫FactoryBean建立bean時就是同步的,而且BeanFactory建立bean時預設是單例的,也就意味著FactoryBean的getObject方法在BeanFactory中定義為單例的時候只會呼叫一次。但有一種情況例外,那就是如果定義bean時指定了“lazy-init=true”時,那就意味著該bean只有在用到的時候才會進行初始化,這個時候如果剛好兩個執行緒同時需要使用,就會出現在兩個執行緒中同時呼叫
此外,需要注意的是FactoryBean的isSingleton方法返回結果表示當前FactoryBean產生的bean是否是單例形式,即每次請求getObject()方法返回的是否都是同一個bean物件。其實FactoryBean更多的是在Spring內部使用,isSingleton只是用來表示當前返回的bean物件是否可以用BeanFactory快取的一個標誌。
上面示例物件的Spring配置檔案如下:
<bean id="userFactoryBean" class="com.xxx.spring.factorybean.UserFactoryBean" lazy-init="false"/>
對於一個FactoryBean介面實現類定義的bean其實Spring將例項化兩個bean,一個是FactoryBean本身對應的bean,另一個是FactoryBean產生的物件對應的bean。所以當我們在通過註解方式注入一個FactoryBean例項對應的bean時,既可以把它當做一個FactoryBean進行注入,也可以把它當做一個對應產生的例項進行注入。而如果是自己直接從ApplicationContext中獲取的話,則直接通過FactoryBean實現類定義的bean名稱獲取到的是FactoryBean實現類產生的物件。如在上面示例中,如果我們通過ApplicationContext的getBean(“userFactoryBean”)獲取到的就將是對應產生的User物件,如果我們需要獲取到對應的FactoryBean本身,則可以在對應的FactoryBean實現類定義的bean名稱前加上“&”進行獲取,如上如果我們要獲取到UserFactoryBean本身,則可以通過ApplicationContext的getBean(“&userFactoryBean”)。如果是通過型別獲取,就可以直接通過User型別或者UserFactoryBean型別獲取到對應的bean物件了。
(注:本文是基於Spring3.1.0所寫)