2011-08-01 21 views
2

在我的main()方法中,我使用Spring創建了一個PersonCollection對象,然後我開始加載不同的Persons對象。超越基本教程的Spring依賴注入

BeanFactory appContext = new ClassPathXmlApplicationContext("cp-beans.xml"); 
PersonCollection pc = appContext.getBean(PersonCollection.class); 
Person aPerson = pc.loadById(1); 
aPerson.doSomething(); 
aPerson.loadById(1067); 
aPerson.doSomething(); 

反過來PersonCollection.loadById()可從分佈式緩存或從Amazon SimpleDB的加載對象:

public Person loadById(int id) throws ConnectException, NoSuchElementException { 
    String memCacheKey = "Person-" + id; 
    Person aPerson = (Person) cache.get(memCacheKey); 
    if (aPerson != null) { 
     return aPerson; //cache hit 
    } 
    aPerson = loadByIdFromSdb(id); //cache miss, read it from SimpleDB 
    cache.set(memCacheKey, aPerson); 
    return aPerson; 
} 

因此,有兩種方法創建一個人,所述第一從分佈式緩存反序列化,在第二個將調用新的Person()並分配所有數據。

人有兩個@Autowired屬性並聲明爲@Service,並且該包位於上下文中:component-scan,但是依賴關係未傳遞,因爲該bean是使用new或從緩存中創建的,而不是與Spring框架。

我可以使用appContext.getBean()來創建Person對象,但是,這意味着要傳遞applicationContext並在應用程序內部使用getBean(),這不正確。

如何解決問題?

更新:我閱讀文檔,並試圖瑞恩·斯圖爾特的建議,並寫了一個小例子項目躍躍欲試。它很好用,謝謝!

https://github.com/stivlo/spring-di

最終,我已經重構我原來的計劃,因爲我並不需要這個功能了一種方法,但就是在我的阿森納的好工具。

回答

5
  1. 是的,避免ApplicationContext.getBean()在你的(非基礎設施)代碼,如瘟疫。
  2. 選項一:不要自動佈線您的POJO類的類。將其拉入與Person緊密耦合的「服務」對象。這或多或少是目前的主流方法,我希望它消失,因爲它變得混亂。
  3. 選項二:使用AspectJ weaving with the @Configurable annotation可以使Person自動裝配,而不管它在哪裏實例化。我非常喜歡這個選項,儘管我還沒有將它用於生產項目。
+0

謝謝你,選項二看起來很有希望:看着它。 – stivlo

+0

+1從來沒有偶然發現選項二,這聽起來非常有希望。 – Daniel

+0

今天我有一個用例,它受益於@Configurable編織。我遵循我自己的源代碼示例,但儘管有很多測試和挫敗感,但直到我添加了時,它才工作 - 這很奇怪,因爲我不喜歡在我的測試項目中沒有這個標籤,它無論如何都可以工作。 – stivlo

1

您可能還需要尋找到所謂ObjectFactoryCreatingFactoryBean有點古怪的實用工具類,這是「重用」的BeanFactory的能力的方式而不擔心bean的名字過度污染業務代碼。

<beans> 
    <bean id="PersonCollection " class="com.example.PersonCollection"> 
     <property name="personMaker" ref="PersonMaker"/> 
    </bean> 

    <bean id="personPrototype" class="com.example.Person" scope="prototype"> 
     <!-- Things to inject onto a newly-made person --> 
    </bean> 

    <bean id="PersonMaker" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean"> 
    <property name="targetBeanName"><idref local="personPrototype"/></property> 
    </bean> 
</beans> 

這樣,您PersonCollection實例不需要了解任何bean的名字,但可以得到一個新的Person(被注入的指定的依賴)通過:

Person p = (Person) this.personMaker.getObject(); 

IMO也有一些它可以變得更加方便(比如使用內部bean而不是idref),但這需要一些Spring-guru和一個自定義的XML名稱空間。

+0

Spring仍然有Person對象被實例化。這裏的問題是如何注入由您的控制之外的代碼管理的實例。主要的例子是Hibernate。 –

+0

我認爲在這種情況下,你可以改變'PersonPrototype' bean的定義來使用'factory-bean'和'factory-method' ......這樣它就可以從外部源(例如Hibernate)獲取結果,但仍然可以在對象被其他組件使用之前,將XML配置的setter-injection應用到對象上。 – Darien

+0

Hibernate不會創建這些對象並將它們交給你。它們是在內部構建的,以響應查詢或加載請求。而其他框架通常並不總是友好,無法爲您提供一個方便的方式讓您自己的實例進入或離開它們。雖然在理論上,你總是可以用反射來破解和削減你的方式,但這實際上並不是一個可行的解決方案。有時純Java並不會削減它。 –