2012-05-14 10 views
3

我有一個關於中型Java Web應用程序中的異常的問題。 有一個使用JDBC實現的數據訪問層,邏輯主要集中在一個servlet中(UI是JSP)。什麼是這樣的應用程序的傳統例外'層次結構?在簡單的數據庫驅動的Java Web應用程序中使用異常

我是否應該捕獲數據訪問層上的異常,並重新引發整個異常(例如DataAccessException)或僅讓最高級別處理它們(servlet)。

另外,我有一個在數據訪問層中調用的連接池,它有它自己的異常類型。是否應該在數據訪問層內捕獲這些異常並將其重新拋出爲DataAccessException,或者應該直接由更高級別處理?

對於2個孩子有一個主應用程序異常是一個好主意:LogicException和TechnicalException。 Logic將具有類似於AuthentificationFailedException等的子類,而TechnicalExceptions將負責傳遞關於數據訪問層異常,FileNotFound(而應該是)等故障的信息?

謝謝!

+0

是否有這些問題的標籤?關於如何大規模構建代碼的問題?我覺得這個話題非常有趣,需要一個好的論壇。 –

回答

2

通常,我用較高級別包裝較低級別的異常,更有意義的異常。這通常是更多的工作,但是可以讓你在層之間解耦。

想象一下,我正在編寫一個恰好從數據庫讀取的配置子系統。如果我不換,我會是這樣的:

public String getConfigurationProperty(String name) throws SQLException { 
    // Try to read from my configuration table 
} 

如果我做了包裝,我會

public String getConfigurationProperty(String name) throws ConfigurationException { 
    try { 
     // Try to read from my configuration table 
    } catch (SQLException ex) { 
     ConfigurationException wrapper = // Some subclass of ConfigurationException that wraps ex 
     throw wrapper; 
    } 
} 

這肯定是更多的工作。其優點是,如果在以後的時間我想改變我的配置後端,比如,基於一個一個文件,而封裝協議我的方法將成爲

public String getConfigurationProperty(String name) throws IOException { 
    // Try to read from my configuration file 
} 

然後,我將不得不改變我所有的客戶端代碼來處理IOException s而不是SQLException s。如果你打包,你只需要改變後端,因爲你的客戶端代碼已經寫在ConfigurationException和它的子類中。請注意,這與您使用選中或未選中的異常無關:如果您要執行異常處理,則幾乎總是需要知道您要處理的異常類型的至少一些近似值。

現在,我傾向於這樣做。有些人認爲大多數例外無論如何都無法妥善處理,而且大部分時間這些包裝都是無稽之談。

public String getConfigurationProperty(String name) throws ConfigurationException { 
    try { 
     // Try to read from my configuration file 
    } catch (IOException ex) { 
     ConfigurationException wrapper = // Some subclass of ConfigurationException that wraps ex 
     throw wrapper; 
    } 
} 
2

在我看到的應用程序中,所有異常都被捕獲到了拋出它們的圖層中,包裝在一個更通用的異常(在您的情況DataAccessException中),然後以這種方式重新拋出。 這是因爲通常發生異常的圖層沒有足夠的關於上下文的信息,所以它無法決定如何以適當的方式處理錯誤。處理這些異常的最佳位置是位於拋出異常的層的右上方的圖層:它具有足夠的信息來「優雅地失敗」,而不會讓該異常在堆棧strace上過多。 在你的情況下,捕獲servlet中的異常將完成這項工作。

但異常的層次結構取決於您正在處理的應用程序。您的邏輯技術部門可能是一個不錯的選擇,或者可能不是。 :)在「異常處理」中沒有「正確的」選擇,並且在單個對中處理這個過於複雜的論據。 :)

1

我也參與開發中型Web應用程序。我們使用的方法是將數據庫層的異常拋出到處理捕獲它們的邏輯的servlet,並向用戶產生正確的錯誤消息。

這是.... 不是要走的國際海事組織。 原因:整個servlet現在依賴於實現。假設我們想切換實現(我們現在想要的)。我們現在需要改變其餘部分的每一個捕獲,因爲新的實現不會拋出同樣的例外。泛型例外是正確的選擇。

不僅例外而且業務對象也應該是通用的。最好是接口。這將允許您更改easilly的實現,而您的locig處理代碼將通過您的servlet整個生命週期依賴於相同的對象。

+0

處理由異常處理創建的依賴關係的方法是「直接超類處理器」:您可以創建一個父類,讓我們說「DataAccessException」,這將是您在try-catch塊中捕獲的異常。但是,您的圖層將拋出該異常的直接子類,讓我們說「DataAccessImpl_1Exception」。通過這種方式處理異常,並且依賴關係綁定更加鬆散:您可以實現另一個「DataAccessImpl_2Exception」,並且仍然會捕獲您的異常......當然,有優點和缺點...... :) – javatutorial

+0

是的,但這是隻有當我寫出拋出的異常時纔有可能。如果我使用第三方庫,我不能讓他們的例外延伸我的。 –

+0

是的,但是你可能會捕獲並在「中間層」中包裝所有這些異常,並重新引發任何你想要的異常。看看gpeche發佈的例子。顯然你必須編寫更多的代碼,但是這些代碼通常已經足夠分離,以便以簡單的方式實現「實現開關」,如果你認爲這些「開關」遲早會發生,那麼值得付出努力。 – javatutorial

2

通常,在應用程序的任何給定層中,您希望捕獲的異常對該層有意義。所以,你不希望在你的Servlet(或MVC控制器)中捕獲一個SybaseException,因爲大概你有一個DAO層來隱藏這個級別的實現細節。

夫婦一般提示:

  • 您應該配置你的apache + servlet容器上的500錯誤返回 明智的頁面。
  • 您的控制器應該將大多數錯誤包含在用戶友好的 消息中。被捕的例外情況應該爲控制者提供足夠的信息來制定合理的信息。
  • 我會考慮繼承RuntimeException與基本應用程序 異常,其中包含技術錯誤消息,以及 本地化的用戶錯誤消息。
  • 想想你想要什麼有一個例外,當你趕上它。設計你的例外,以便它能夠直接做你需要的。

最後,並不是所有人都會同意這一點,但是您可以爲所有異常子類RuntimeException做一個強有力的例子,以便它們不被選中。我已經開發了許多采用這種方法的大型代碼庫,它一般工作正常,並且減少了大量catch-rethrow樣板代碼。僅僅因爲java提供了檢查異常,並不意味着你必須使用它們。這顯然是我的看法,但重要的是要認識到並非所有人都使用檢查的異常,實際上,許多代碼庫將明確地避免它們。

相關問題