2011-11-24 126 views
4

我在這裏發現了類似的問題Spring - how to inject a bean into class which is created many times at runtime?Why is Spring's ApplicationContext.getBean considered bad?,但都沒有真正回答我的情況。如何注入彈簧豆異常

示例代碼:

public interface AppNameProvider 
{ 
    String getAppName(); 
} 

public class DefaultAppNameProvider implements AppNameProvider 
{ 
    private String appName; 

    public String getAppName() 
    { 
     return appName; 
    } 

    public setAppName(String appName) 
    { 
     this.appName = appName; 
    } 
} 

<bean id="appNameProvider" class="some.package.DefaultAppNameProvider"> 
    <property name="appName" value="MyApplication"/> 
</bean> 

public class MyException extends RuntimeException 
{ 
    // Imagine obligatory constructors here... 

    public String getAppName() 
    { 
     // Inject appNameProvider somehow here 
     return appNameProvider.getAppName(); 
    } 
} 

我在XML聲明提供商豆。在這個例子中,爲了簡單起見,在xml中簡單地聲明瞭該值。我有一個自定義的異常,需要從bean中接收一些東西。如何將這樣的bean注入到異常類中。我顯然不能將異常聲明爲Spring bean。 appName只是一個簡單的例子,它可以是其他任何東西。您可能想知道爲什麼myException.getAppName()的假設調用者不會僅僅調用appNameProvider.getAppName()?因爲它並非如此,例如在每個異常中可能會有不同的提供者等。

我想知道如何將bean注入這種異常。我可以在異常拋出時添加setter並設置提供者。但是我必須知道從外部使用哪個提供程序(在我的應用程序代碼中),並且我必須在要引發此異常的任何地方冗餘地執行此操作。理想情況下,我想聲明哪個提供程序用於xml中的異常。

最終問題可以擴大,所以我們不會想到異常,而是想到任何不是bean本身的運行時對象。

PS我不害怕在代碼中有Spring的硬編碼依賴關係。我使用Spring,我想擁抱它 - 不是避免它。

+0

你能發佈拋出一個'MyException'的新實例的代碼嗎?我不知道你是否無法通過構造函數傳遞給AppNameProvider的引用... – JBert

回答

1
  1. 注入其中拋出異常
  2. 提供了被利用到提供者設置爲異常的構造函數/ setter方法的類提供
  3. throw new MyException(provider)
+0

Bozho和JBert的答案: 我可以添加setter並在異常拋出時設置提供程序。但是我必須知道從外部使用哪個提供程序(在我的應用程序代碼中),並且我必須在要引發此異常的任何地方冗餘地執行此操作。 – user1063845

+0

@ user1063845事情是,我想知道在什麼情況下你會拋出異常,爲什麼你實際上需要在你捕獲它的地方的AppnameProvider。我期望當你拋出一個異常時,有人在實現AppnameProvider的類上做了錯誤的操作,這意味着你有__擁有提供者的實例。我相信Spring可以做一些魔術技巧,但是爲了達到它,聽起來就像你試圖修復你設計中的一個缺陷。你需要做這項工作的Spring魔法可能會讓代碼難以理解,任何後來在代碼上工作的人都會覺得難以理解。 – JBert

0

您可以創建一個組件,並在其中注入資產。例如,您可以將DefaultAppNameProvider定義爲一個組件,因此您可以自動裝載其中的其他組件。然後,您可以使用帶有私有構造函數的單例設計模式來提供名爲getInstance的靜態方法。在類MyException中,您可以使用DefaultAppNameProvider.getInstance().getAppName()訪問DefaultAppNameProvider屬性。

單例組件的代碼示例。

@Component 
public class DefaultAppNameProvider { 
    private static DefaultAppNameProvider instance; 

    private DefaultAppNameProvider() { 
     instance = this; 
    } 

    public static DefaultAppNameProvider getInstance() { 
     return instance; 
    } 

    private String appName; 

    public String getAppName() 
    { 
     return appName; 
    } 

    public setAppName(String appName) 
    { 
     this.appName = appName; 
    } 
} 
0

我一直在平均時間環顧四周。我發現this。最後我使用了以下解決方案。

根據1創建ApplicationContextProvider:

public class ApplicationContextProvider implements ApplicationContextAware 
{ 
    private static ApplicationContext applicationContext; 

    public static ApplicationContext getApplicationContext() 
    { 
     return applicationContext; 
    } 

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException 
    { 
     ApplicationContextProvider.applicationContext = applicationContext; 
    } 
} 

然後AppNameProviderFactory它映射供應商的密鑰。主鍵可以爲例外名稱:

public class AppNameProviderFactory 
{ 
    private Map<String,AppNameProvider> map; 

    public void setMap(Map<String, AppNameProvider> map) 
    { 
     this.map = map; 
    } 

    public AppNameProvider getAppNameProvider(String key) 
    { 
     return map.get(key); 
    } 
} 

以XML我定義映射:

<bean id="appNameProviderFactory" class="some.domain.AppNameProviderFactory"> 
    <property name="map"> 
     <map> 
      <entry key="MyException" value-ref="appNameProvider"/> 
     </map> 
    </property> 
</bean> 

終於在異常類:

public class MyException extends RuntimeException 
{ 
    // Imagine obligatory constructors here... 

    public String getAppName() 
    { 
     final ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext(); 
     AppNameProviderFactory factory = (AppNameProviderFactory) applicationContext.getBean("appNameProviderFactory"); 
     return factory.getAppNameProvider("MyException").getAppName(); 
    } 
} 

這樣,我在xml配置,與業務代碼分離。根據需要,我可以爲不同的提供者提供許多例外。

謝謝大家的建議。 PS爲簡單起見,錯誤處理和NPE處理已被忽略。