プロジェクトの作成 - Spring Initializr
今回は、組み込みデータベースを使用した、デモアプリケーションを作成します。ここでは、Spring Initializr を使用したプロジェクトの作成方法、Spring における基本的な責務の分割方法、およびこれを反映したパッケージの構成を学びます。
Spring Initializr
Spring プロジェクトを作成する場合、現在最も簡単に、目的の依存関係を整える方法が、Spring Initializr を使用したものになります。以下のコマンドを実行することで、プロジェクトのセットアップが完了します。なお以下の例では、groupId
や、packageName
に、io.github.yo1000
を使用していますが、適宜 yo1000
の部分を、お手持ちの Github アカウントに差替えて指定するようにしてください。
$ curl https://start.spring.io/starter.tgz \
-d dependencies="web,hateoas,thymeleaf,jdbc,hsql,aop" \
-d language="java" \
-d javaVersion="1.8" \
-d packaging="jar" \
-d bootVersion="1.3.0.RELEASE" \
-d type="maven-project" \
-d groupId="io.github.yo1000.sss" \
-d artifactId="self-study-spring" \
-d version="0.0.1-SNAPSHOT" \
-d name="self-study-spring" \
-d description="Self study for Spring Boot" \
-d packageName="io.github.yo1000.sss" \
-d baseDir="self-study-spring" \
-d applicationName="SelfStudySpringApplication" \
| tar -xzvf -
使用可能なすべてのオプションは、以下のコマンドで確認できます。
$ curl start.spring.io
お手持ちの環境で、 curl
が使用できない場合、https://start.spring.io/ へアクセスすることでも、同様のプロジェクト作成を行うことができます。
プロジェクトが作成できたら、以下のコマンドを使用して、起動を確認します。なお、Spring Boot では、デフォルトで 8080
ポートが使用されます。もしすでに 8080
ポートが使用されている場合は、./mvnw spring-boot:run
の後ろにスペースを空けて、--server.port={任意のポート番号}
オプションをつけてください。
$ cd self-study-spring
$ ./mvnw spring-boot:run
起動が確認できたら、Ctrl+C
キーでプロセスを終了してください。
Spring Initializr で作成したプロジェクトには mvnw
が同梱されており、これを使用すると、環境へ事前に Maven を用意しておくことなく、Maven によるビルドが可能になります。なお、Windows を使用している場合は、mvnw.cmd
が使用できます。
mvnw
の実行モジュール本体は、同じく同梱されている .mvn/wrapper/maven-wrapper.jar
になります。GitHub で作成される .gitignore
には、デフォルトで *.jar
が含まれているため、プロジェクトを公開する場合などには、.mvn/wrapper/maven-wrapper.jar
もバージョン管理されるように、.gitignore
を適宜編集するようにしてください。
Spring における責務の分割
Spring では、責務に応じていくつかのアノテーションが用意されています。これらを適切に使用することで、自然と責務の分割が進み、見通しや、テストの書きやすさに優れた、保守性の高いコードとなっていきます。Spring を使用した開発を行うにあたって、この考え方の把握は最も重要なステップのひとつです。次章以降で実際にコードを書き始める前に、必ず押さえておくようにしてください。
下図は、各責務レイヤー間がどのように連携しあうかを、簡単に俯瞰できるようにしたものです。
それぞれにどのような責務があり、どのようなアノテーションが対応しているか、見ていきます。
Configuration
コンフィグレーションレイヤーを担当し、構成管理や設定などを表現します。アノテーションは、@Configuration
が対応します。
View
ビューレイヤーを担当し、リクエスト元へのレスポンスを表現します。
Spring では、リクエスト元にレスポンスされるものは、いずれもビューとみなされます。HTML 書式のものだけでなく、JSON、XML、CSV、PDF、他も、等しくビュー表現のひとつとして扱われます。
Controller
コントローラーレイヤーを担当し、エンドポイント、サービス、ビューの紐付けを表現します。アノテーションは、@Controller
、および @RestController
が対応します。
コントローラーレイヤーでは、リクエスト、およびレスポンスのハンドリングのみを行います。共通的な例外レスポンスや、レスポンス書式の変換処理については、後述する @ContorollerAdvice
を併せて利用します。
Service
サービスレイヤーを担当し、業務処理や、業務の流れを表現します。アノテーションは、@Service
が対応します。
リクエスト、レスポンスに依存したような処理や、永続化処理は、このレイヤーで表現すべきではありません。これら、他責務の処理記述が混在しはじめると、テストの難易度は著しく向上していきます。
Repository
リポジトリーレイヤーを担当し、永続化を表現します。アノテーションは、@Repository
が対応します。
実装に際しては、具象クラスの他に、抽象化されたインターフェースを定義しておくことを強く推奨します。抽象化しておくことで、例えばデータソースが、RDB から、KVS に変更された場合など、他責務レイヤーへの影響が最小化され、変更をリポジトリーレイヤーのみに閉じることができます。
Template
テンプレートレイヤーを担当し、データソースの直接的な操作を表現します。
テンプレートは、各データソースと、その永続化方法に応じた、直接的な永続化操作を表現するため、サポートされうる限り、その組み合わせの分だけ種類があります。(テンプレート = データソースタイプ x 永続化手法)
例えば、RDB をデータソースとした、JDBC による永続化手法を表現するテンプレートには JdbcTemplate
が存在し、同じく RDB をデータソースとした MyBatis による永続化手法を表現するテンプレートには SqlSessionTemplate
が存在します。一方、MongoDB をデータソースとした場合には MongoTemplate
が存在するなど、様々なデータソース、永続化手法に応じてテンプレートが用意されています。
Model
データモデルレイヤーを担当します。アノテーションは、必ずしも必要ではありませんが、永続化手法に応じて、@Entity
や、@Document
が必要となる場合があります。
アノテーションによるフィールドバリデーション等の表現を除き、原則 POJO であることが望ましいです。
Advice (AOP)
AOP レイヤーを担当します。アノテーションは、@Aspect
、および @ControllerAdvice
が対応します。
@Aspect
は、それ単体では DI コンテナに登録されないため、@Component
や @Bean
と組み合わせて使用します。また、ビューレイヤー、コントローラレイヤー間における処理の多くは、@Aspect
で、割り込みを行うことができないため、この箇所への割り込みには @ControllerAdvice
を利用します。
AOP は、メソッドの前や後、または前後に共通的な処理を後付けすることができ、同じような処理を何度も記述するのを抑制したり、本来の責務とは直接関係のない処理を、各責務から分離したりするのに非常に役立ちます。
例えば、パフォーマンスログの出力や、トランザクション境界の定義などを AOP に分離することができます。
パッケージ構成
ここまでで紹介した責務の分割を考慮したうえで、パッケージを構成してみます。yo1000
となっている部分については、適宜ご自身の環境に応じて、読み替えてください。
$ PACKAGE_BASEDIR='src/main/java/io/github/yo1000/sss'; \
mkdir -p ${PACKAGE_BASEDIR}/aspect; \
mkdir -p ${PACKAGE_BASEDIR}/config; \
mkdir -p ${PACKAGE_BASEDIR}/controller/api/v1; \
mkdir -p ${PACKAGE_BASEDIR}/controller/page; \
mkdir -p ${PACKAGE_BASEDIR}/model; \
mkdir -p ${PACKAGE_BASEDIR}/repository/jdbc; \
mkdir -p ${PACKAGE_BASEDIR}/service; \
mkdir -p ${PACKAGE_BASEDIR}/util; \
mkdir -p src/main/resources/db/migration; \
touch ${PACKAGE_BASEDIR}/aspect/.gitkeep; \
touch ${PACKAGE_BASEDIR}/config/.gitkeep; \
touch ${PACKAGE_BASEDIR}/controller/api/v1/.gitkeep; \
touch ${PACKAGE_BASEDIR}/controller/page/.gitkeep; \
touch ${PACKAGE_BASEDIR}/model/.gitkeep; \
touch ${PACKAGE_BASEDIR}/repository/jdbc/.gitkeep; \
touch ${PACKAGE_BASEDIR}/service/.gitkeep; \
touch ${PACKAGE_BASEDIR}/util/.gitkeep; \
touch src/main/resources/db/migration/.gitkeep; \
touch src/main/resources/static/.gitkeep; \
touch src/main/resources/templates/.gitkeep; \
mv src/main/resources/application.properties src/main/resources/application.yml
$ pwd; find . | grep -v '/target' | grep -v '/.git' | sort | sed -E '1d; s/^.//; s/\/([^/]*)$/|__ \1/; s/\/[^/|]*/| /g'
~/self-study-spring
|__ .mvn
| |__ wrapper
| | |__ maven-wrapper.jar
| | |__ maven-wrapper.properties
|__ mvnw
|__ mvnw.cmd
|__ pom.xml
|__ src
| |__ main
| | |__ java
| | | |__ io
| | | | |__ github
| | | | | |__ yo1000
| | | | | | |__ sss
| | | | | | | |__ SelfStudySpringApplication.java
| | | | | | | |__ aspect
| | | | | | | |__ config
| | | | | | | |__ controller
| | | | | | | | |__ api
| | | | | | | | | |__ v1
| | | | | | | | |__ page
| | | | | | | |__ model
| | | | | | | |__ repository
| | | | | | | | |__ jdbc
| | | | | | | |__ service
| | | | | | | |__ util
| | |__ resources
| | | |__ application.yml
| | | |__ static
| | | |__ templates
| |__ test
| | |__ java
| | | |__ io
| | | | |__ github
| | | | | |__ yo1000
| | | | | | |__ sss
| | | | | | | |__ SelfStudySpringApplicationTests.java
以上で、プロジェクトの作成は完了です。次章からは、責務の分割図の左側 (リクエストに最も近い側) から順に、実際にクラスを作成していきます。
参考
- https://start.spring.io/
- https://github.com/spring-io/initializr
- https://github.com/spring-io/initializr/wiki/Metadata-format
サンプル
ここまでのコードサンプルは、以下より入手できます。
$ git clone -b chapter/1 https://github.com/yo1000/self-study-spring.git