web-dev-qa-db-ja.com

サービス層はすべてのdao例外をキャッチし、サービス例外としてラップする必要がありますか?

3つのレイヤーのSpring Webアプリがあります。dao、service、controllersです。コントローラーがdaoを直接呼び出すことはありません。サービスレイヤーを通じて行われます。現在、ほとんどの場合、処理されないdao例外(実行時)があると、JSPによってキャッチされ、エンドユーザーにエラーメッセージが表示されます。サービス層はすべてのdao例外をキャッチし、サービス例外としてラップする必要がありますか?

try {
   daoInstance.someDaoMethod();
} catch(DataAccessException dae) {
   throw new ServiceException("message", dae);
}

ServiceExceptionもランタイムであり、どちらも処理されていないと仮定しましょう。 ServiceExceptionの代わりにDataAccessExceptionをスローするだけの違いはありますか?私はプレゼンテーション層がデータアクセス例外について知っているべきではないと思いました。しかし、それらをラップするためだけに、回復不能な例外をキャッチする意味はわかりません。

25
Oscar

重要な要素はあなたのサービスクライアントが誰であるかだと思います。

サービスレイヤーが自分のプロジェクトのレイヤー間のアーキテクチャの境界にすぎず、サービスクライアントが同じ信頼レルム内にある場合は、物事を緩和し、チェックされていない例外をコントローラーレイヤーまたはサービスクライアントにバブリングできます。

ただし、一般向けコードの場合。サードパーティまたは顧客によって消費されるサービスでは、チェックされていない例外をサービス指向の例外でラップするほうが、主にセキュリティ上の懸念から、次に疎結合とクリーンな抽象化のために、よりクリーンだと思います。

データレイヤーの例外は決して、ウェブアプリケーションのエンドユーザーに直接届かないようにする必要があります。スキーマ、クエリ、行番号情報、変数または関数名などの内部情報が含まれている可能性があります。エンドユーザーの例外は、安全な設定でサニタイズできます。

外部サービスクライアントは、実装の詳細には関係なく、バグまたは環境の問題であるため、未チェックの例外を処理できません。安全なアプリケーションでは、データベースエラーは、伝播するほど安全ではありません。挿入された3番目のテーブルである_OracleException - ORA-01234 - ..._です。クライアントは、処理できるチェック済み/予期された例外を処理し、その他すべてを潜在的なバグレポートとして扱うことを許可する必要があります。サービスコントラクトは、アトミックで一貫性のあるトランザクション抽象化である必要があります。それが例外について何もできない場合、残っている唯一の有用なことはバグレポートを与えることです。例外をログに記録する機能はすでにあるので、なぜエンドユーザーに詳細を負担させるのでしょうか。アプリは監視できるため、ユーザーが報告する前に、チェックされていない例外についてすでに知っています。

eat例外を許容することはできません。また、私はチェック例外のファンではありませんが、全体の性質に適した計画を持つことを好みます製品。

20
codenheim

いいえ、DAO例外をWebアプリケーションでラップしないでください

ゼロの利益のためにコードに多くのノイズがあります。 DAO例外は、正当な理由で未チェックの例外です。アプリケーションコードは、DAO例外からの回復に役立つことはできません。本当の問題はここにあります:

...エンドユーザーにエラーメッセージを表示するJSPによってキャッチされます。

コードベース全体を破壊するのではなく、この問題を1か所で修正します。

キャッチされなかった例外をユーザーに表示する方法を制御します。キャッチされなかった例外は、アプリケーションのバグまたは基盤となるシステムの障害が原因です。ユーザーに、要求を処理できなかった理由に関する情報を提供する理由はありません。ユーザーができることは何もありません。やらなければならないのは、わかりやすいエラーページを表示することだけです。

注:たとえば、単純にラップして再スローする一連のキャッチブロックを作成するなど、多くの面倒なコードを記述している場合、ほとんどの場合、より良い解決策があります。

13
kevin cline

例外ラッピングを使用する主な理由は、ビジネス層のコードがすべての可能な例外について知る必要がないようにするためですシステム内。これには主に2つの理由があります。

  • 一貫性:宣言された例外は、呼び出しスタックの上位に向かって集計されます。例外をラップせずに、それらをスローするメソッドを宣言することによってそれらを渡す場合、多くの異なる例外を宣言するトップレベルのメソッドになってしまう可能性があります。コールスタックをバックアップする各メソッドでこれらすべての例外を宣言するのは面倒になります。

  • カプセル化:トップレベルのコンポーネントに、ボトムレベルのコンポーネントや、それらがスローする例外について何も知らせたくない場合があります。たとえば、DAOのインターフェイスと実装の目的は、データアクセスの詳細をアプリケーションの他の部分から抽象化することです。ここで、DAOメソッドがSQLExceptionをスローする場合、DAOを使用するコードはそれらをキャッチする必要があります。データベースからではなくWebサービスからデータを読み取る実装に変更した場合はどうなりますか?次に、DAOメソッドはRemoteExceptionとSQLExceptionの両方をスローする必要があります。また、ファイルからデータを読み取るDAOがある場合は、IOExceptionもスローする必要があります。これは3つの異なる例外であり、それぞれが独自のDAO実装にバインドされています。

それで、要するに、答えはイエスです!

8
fabienbk