JSUG(日本Springユーザ会)の下記勉強会向けのサンプル実装です。
- 2014/11/27 「SpringBootを用いたドメイン駆動設計」
Spring Boot 3 の利用に伴い実装コードを Java17 へ切り替えています。 Java7 での実装コードを確認したいときは 1.x ブランチを参照してください。
本サンプルではSpringBootとLombokを利用してドメインモデリングの実装例を示します。実際に2007年くらいから現在に至るまで現場で利用されている実装アプローチなので、参考例の一つとしてみてもらえればと思います。
※JavaDocに記載をしていますが、サンプルに特化させているので実際の製品コードが含まれているわけではありません。
認証含む、より実践的な実装サンプルについてはsample-boot-hibernateを参照してください。
またUI側の実装サンプルについてはsample-ui-vue / sample-ui-reactを参照してください。
オーソドックスな三層モデルですが、横断的な解釈としてインフラ層を考えます。
- UI層 - ユースケース処理を公開(必要に応じてリモーティングや外部サイトを連携)
- アプリケーション層 - ユースケース処理を集約(外部リソースアクセスも含む)
- ドメイン層 - 純粋なドメイン処理(外部リソースに依存しない)
- インフラ層 - DIコンテナやORM、各種ライブラリ、メッセージリソースの提供
UI層の公開処理は通常Thymeleafを用いて行いますが、本サンプルでは異なる種類のクライアント利用を想定してRESTfulAPIでの公開を前提とします。(API利用前提のサーバ解釈)
SpringBootは様々な利用方法が可能ですが、本サンプルでは以下のポリシーを用います。
- DBの設定等、なるべく標準定義をそのまま利用する。
- 設定ファイルはymlを用いる。Bean定義にxml等の拡張ファイルは用いない。
- ライブラリ化しないので@Beanによる将来拡張性を考慮せずにクラス単位でBeanベタ登録。
- 例外処理は終端(RestErrorAdvice/RestErrorCotroller)で定義。
- サンプル用途
Java17以上を前提としていますが、従来のJavaで推奨される記法と異なっている観点も多いです。
以下は保守性を意識した上で簡潔さを重視した方針となっています。
- Lombokを積極的に利用して冗長さを排除
- 名称も既存クラスと重複しても良いのでなるべく簡潔に
- インターフェースの濫用をしない
- ドメインの一部となるDTOなどは内部クラスで表現
パッケージ/リソース構成については以下を参照してください。
main
java
sample
context … インフラ層
controller … UI層
model … ドメイン層
usecase … アプリケーション層
util … 汎用ユーティリティ
- Application.java … 実行可能な起動クラス
resources
- application.yml … 設定ファイル
- messages-validation.properties … 例外メッセージリソース
- messages.properties … メッセージリソース
サンプルユースケースとしては以下を想定します。
- 口座残高100万円を持つ顧客が出金依頼(発生 T, 受渡 T + 3)をする。
- システムが営業日を進める。
- システムが出金依頼を確定する。(確定させるまでは依頼取消行為を許容)
- システムが受渡日を迎えた入出金キャッシュフローを口座残高へ反映する。
サンプルはGradleを利用しているので、IDEやコンソールで動作確認を行うことができます。
開発IDEであるVSCodeで本サンプルを利用するには、事前に以下の手順を行っておく必要があります。
- Java17以上のインストール
- DevContainer 利用時は不要
- Java / Lombok / Gradle の Extension 追加
次の手順で本サンプルをプロジェクト化してください。
- ダウンロードしたjava-dddディレクトリ直下へコンソールで移動
- 「code .」で起動
次の手順で本サンプルを実行してください。
- 左サイドメニューの「Run And Debug」で Run ddd-java を選択肢て実行
- DEBUG CONSOLEタブに「Started Application」という文字列が出力されればポート8080で起動が完了
Linux や WSL 上で DevContainer を立ち上げて確認することも可能です。 Open Container のダイアログが出たらOKを押下してください。 DevContainer の起動に失敗する時はポート重複が無いか、vscode-remote-release の #7303 の問題を踏んでいないか確認してください。 #7303 の問題だった時は Extension の DevContainers を
v0.251.0
へ下げることでうまくいくことがあります。
開発IDEであるSTSで本サンプルを利用するには、事前に以下の手順を行っておく必要があります。 ※EclipseにSpringIDEプラグインを入れても可
- Java17以上のインストール
- Lombokのパッチ当て(.jarを実行してインストーラの指示通りに実行)
次の手順で本サンプルをプロジェクト化してください。
※コンパイルエラーになる時は、Javaコンパイラの設定が17以上になっているかを確認してください。
- パッケージエクスプローラから「右クリック -> Import」でExsisting Project into Workspaceを選択してNextを押下
- Root folder:にダウンロードしたddd-javaディレクトリを指定してBuild Modelを押下
- Projectでddd-javaを選択後、Finishを押下(依存ライブラリダウンロードがここで行われます)
次の手順で本サンプルを実行してください。
- Application.javaに対し「右クリック -> Run As -> Java Application」
- Consoleタブに「Started Application」という文字列が出力されればポート8080で起動が完了
Windows/Macのコンソールから実行するにはGradleのコンソールコマンドで行います。
※事前にJava17以上のインストールが必要です。
- ダウンロードしたjava-dddディレクトリ直下へコンソールで移動
- 「gradlew bootRun」を実行
- コンソールに「Started Application」という文字列が出力されればポート8080で起動が完了
STSまたはコンソールで8080ポートでサーバを立ち上げた後、ブラウザから下記URLへアクセスする事でRESTfulAPIの実行テストを実施可能です。
※本来なら情報更新系処理はPOSTで取り扱うべきですが、UIの無いデモ用にGETでのアクセスを許容しています。
※パラメタは?key=valueで繋げて渡してください。
顧客向けユースケース
- http://localhost:8080/asset/cio/withdraw
- 振込出金依頼 [accountId: sample, currency: JPY, absAmount: 出金依頼金額]
- http://localhost:8080/asset/cio/unprocessedOut
- 振込出金依頼未処理検索
社内向けユースケース
- http://localhost:8080/admin/asset/cio
- 振込入出金依頼検索 [updFromDay: 更新From(yyyyMMdd), updToDay: 更新To(yyyyMMdd)]
バッチ向けユースケース
- http://localhost:8080/system/job/daily/processDay
- 営業日を進める(単純日回しのみ)
- http://localhost:8080/system/job/daily/closingCashOut
- 当営業日の出金依頼を締める
- http://localhost:8080/system/job/daily/realizeCashflow
- 入出金キャッシュフローを実現する(受渡日に残高へ反映)
本サンプルのライセンスはコード含めて全てMIT Licenseです。
Spring Bootを用いたプロジェクト立ち上げ時のベース実装サンプルとして気軽にご利用ください。