使用FactoryBean接口實現自定義bean初始化

使用FactoryBean接口實現自定義bean初始化

 

       本文所要介紹的FactoryBeanSpring中定義的一個接口,當把它的實現類定義爲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時默認是單例的,也就意味着FactoryBeangetObject方法在BeanFactory中定義爲單例的時候只會調用一次。但有一種情況例外,那就是如果定義bean時指定了“lazy-init=true”時,那就意味着該bean只有在用到的時候纔會進行初始化,這個時候如果剛好兩個線程同時需要使用,就會出現在兩個線程中同時調用FactoryBeangetObject方法進行bean的初始化,如不加控制就會出現兩個實例。爲保證只有一個實例,getObject方法內部需要是同步的。

       此外,需要注意的是FactoryBeanisSingleton方法返回結果表示當前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實現類產生的對象。如在上面示例中,如果我們通過ApplicationContextgetBean(“userFactoryBean”)獲取到的就將是對應產生的User對象,如果我們需要獲取到對應的FactoryBean本身,則可以在對應的FactoryBean實現類定義的bean名稱前加上“&”進行獲取,如上如果我們要獲取到UserFactoryBean本身,則可以通過ApplicationContextgetBean(“&userFactoryBean”)。如果是通過類型獲取,就可以直接通過User類型或者UserFactoryBean類型獲取到對應的bean對象了。

 

(注:本文是基於Spring3.1.0所寫)

 

 

 

 

 

 

 

 

 

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