2011-02-11 31 views
28

FactoryBean可用於以編程方式創建可能需要複雜實例化邏輯的對象。如何獲取由FactoryBean spring創建的bean管理?

然而,似乎FactoryBean創建豆子不會成爲春季管理。這個解釋是否正確?如果是這樣,有沒有什麼好的解決方法?包含一個簡短的代碼示例來說明我的問題。

的ApplicationContext:

<bean id="searcher" class="some.package.SearcherFactory" /> 
<bean id="service" class="some.package.Service" /> 

工廠實現:通過工廠創建

public class SearcherFactory implements FactoryBean<Searcher> { 

    @Override 
    public Searcher getObject() throws Exception { 
     return new Searcher(); // not so complex after all ;) 
    } 

    @Override 
    public Class<Searcher> getObjectType() { 
     return Searcher.class; 
    } 
    .... 
} 

類:

public class Searcher() { 
     private Service service; 

     @Autowired 
     public void setService(Service service) { 
      // never invoked 
      this.service=service; 
     } 
} 

回答

17

FactoryBean創建的對象是由Spring管理,但沒有實例化或由Spring配置。通過使用FactoryBean,您自己承擔責任。所有注入和配置必須由FactoryBean

處理有一個替代方案可能會更好地爲你工作 - 使用annotation-based config instead of XML-based config。這意味着您可以在Java中擁有複雜的實例化邏輯,同時仍然在對象本身上使用諸如@Autowired之類的東西。

我傾向於現在對所有非平凡的Spring應用程序使用註解風格的配置,它使許多事情變得更容易。

+0

+1。我剛剛開始使用基於註釋的配置來處理這些類型的場景。 – Fil 2011-02-11 16:54:38

+5

那麼,你會如何解決作者的問題?你能用適當的java配置更新答案嗎? – 2015-01-07 01:16:38

4

手動的方法是:

  1. 注入工廠bean中的依賴項
  2. 在目標對象上手動設置它們。

您也可以注入在工廠bean ApplicationContext(或通過實施ApplicationContextAware得到它),並做ctx.getAutowireCapableBeanFactory().autowireBean(bean)

我承認雙方感到陌生,雖然。

但實際上,如果邏輯很簡單(只實例化),則使用prototype作用域。

+0

它可以工作,並且至少可以將彈簧聯軸器減少到單個工廠級別。 – 2011-02-11 15:25:51

-3

不,由FactoryBean創建的bean也由spring管理。

+7

這個答案只是誤導。這沒有錯,bean是被管理的,但不是bean的依賴關係。 – 2011-02-11 15:37:19

27

這裏是一個抽象FactoryBean實現,它自動裝配您:

public abstract class AbstractAutowiringFactoryBean<T> extends 
    AbstractFactoryBean<T> implements ApplicationContextAware{ 

    private ApplicationContext applicationContext; 

    @Override 
    public void setApplicationContext(
     final ApplicationContext applicationContext){ 
     this.applicationContext = applicationContext; 
    } 

    @Override 
    protected final T createInstance() throws Exception{ 
     final T instance = doCreateInstance(); 
     if(instance != null){ 
      applicationContext 
       .getAutowireCapableBeanFactory() 
       .autowireBean(instance); 
     } 
     return instance; 
    } 

    /** 
    * Create the bean instance. 
    * 
    * @see #createInstance() 
    */ 
    protected abstract T doCreateInstance(); 

} 

擴展它,實現getObjectType()doCreateInstance()方法,你是啓動和自動裝配運行。

注意: BeanPostProcessor不適用,這將需要額外的代碼。

+1

這不是一個壞主意,要麼提高可重用性。雖然我很想知道爲什麼這些還沒有作爲我們的朋友在Springource提供的模板提供。 – 2011-02-11 23:18:24

17

這是怎麼回事?

<bean id="serviceFactory" 
     class="some.package.SearcherFactory" /> 


<bean id="service" 
     factory-bean="serviceFactory" 
     factory-method="getObject"/> 

...然後只需注入豆「服務」,並不在乎工廠在你的代碼

0

一個FactoryBean是一個接口,你作爲一個開發者,實現書寫時工廠類而你希望由Spring派生的工廠類創建的對象作爲bean進行管理,而另一方面,BeanFactory代表Spring IoC容器,它包含託管bean並提供檢索它們的途徑。它是實現控制容器反轉的基本功能的框架核心的一部分。

在大多數情況下,您不會直接使用或實現BeanFactory接口,除非您要擴展框架的核心功能。雖然當您有由需要由Spring管理的工廠創建的對象時,您會執行FactoryBean。

簡而言之,BeanFactory表示Spring容器,而FactoryBean表示創建的對象被拾取並在容器中註冊爲bean的工廠類。

File: context.xml 

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation=" 
       http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd"> 

    <bean id="sha" class="MessageDigestFactoryBean"> 
     <property name="algorithm" value="SHA1"/> 
    </bean> 

    <bean id="md5" class="MessageDigestFactoryBean"/> 

</beans> 


File: Main.java 

import java.security.MessageDigest; 

import org.springframework.beans.factory.FactoryBean; 
import org.springframework.beans.factory.InitializingBean; 
import org.springframework.beans.factory.xml.XmlBeanFactory; 
import org.springframework.core.io.ClassPathResource; 

public class Main { 
    public static void main(String[] args) { 
    XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("context.xml")); 
    String d1 = (String) factory.getBean("sha"); 
    String d2 = (String) factory.getBean("md5"); 
    System.out.println(d1); 
    System.out.println(d2); 
    } 

} 

class MessageDigestFactoryBean implements FactoryBean, InitializingBean { 
    private static final String DEFAULT_ALGORITHM = "MD5"; 

    private String algorithm = DEFAULT_ALGORITHM; 

    public Object getObject() throws Exception { 
    return this.algorithm; 
    } 

    public Class getObjectType() { 
    return MessageDigest.class; 
    } 

    public boolean isSingleton() { 
    return true; 
    } 

    public void setAlgorithm(String algorithm) { 
    this.algorithm = algorithm; 
    } 

    public void afterPropertiesSet() throws Exception { 
    this.algorithm += " after setting"; 
    } 
}