Featured image of post 【マイクロサービス】流行りのSpring Boot 2 + Gradle + Java8でマルチプロジェクトな個人開発をしていこう 環境構築編【DDD(ドメイン駆動設計)】

【マイクロサービス】流行りのSpring Boot 2 + Gradle + Java8でマルチプロジェクトな個人開発をしていこう 環境構築編【DDD(ドメイン駆動設計)】

4435文字

お勉強のためのシステムを作ってみようと思った今日この頃

新鮮な知識を求めて

筆者は普段はJava+SpringBoot(1系)を取り扱ったシステム開発を行っています。

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".

We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need very little Spring configuration.Spring Boot

上記の環境については、それなりに知識がついてきていると思っています。

しかし、日々進化するIT業界。。。
いつまでも同じ技術だけで生きていけるはずはありません。

個人事業主なら尚更です・・・!ガクガク((( ;゚Д゚)))ブルブル

Spring Boot2系を覚えよう

とはいえ、今後もJavaを武器にしていきたい気持ちは変わりません。
なんだかんだでメジャーな言語ですしね!

そして、Javaのサーバーサイド開発といえば、今やSpringフレームワークが一強となってきているのもまた事実。

そんな中SpringBoot2が最近リリースされまして、触ったことがなかったので勉強とアウトプットの目的を兼ねて、いろいろと個人開発をしながらやったことを記事にまとめていこうと思います!

[adsense-responsive]

ゆくゆくはサーバーサイドKotlinフロントエンドの勉強AWSやGCPなどへのデプロイなどもご紹介していければなと思います♪

そんなわけで、今回はSpringBoot2+Gradleを取り扱ったマルチプロジェクト開発の土台作りをご紹介していこうと思います♪

手順

注意

今回は筆者の好みを踏まえたマルチプロジェクトの設定をご紹介していきます。

筆者の理想の開発思想としては以下の点を念頭におくようにしています。

設計思想
  • DDD(ドメイン駆動設計)
  • マイクロサービス
  • 極力疎結合
  • ソース=ドキュメント
  • MVCレイヤー思想

こんな感じですね。

ですので、あくまで皆さんの理想の開発環境構築を手助けするための参考程度に捉えて頂ければなと思います!!!

Spring Initializrでプロジェクトの作成

今回はSpring Initializrを使ってプロジェクトの雛壇を作ろうと思います。

Spring InitializrBootstrap your application · Github | Twitter. Help us improve the site! Take a quick survey. Project. Maven Project. Gradle Project. Language. Java. Kotlin. Groovy. Spring Boot. Spring Initializr

今回は以下の通りのアーキで作成しました。

ProjectGradle Project
Language2.1.3
PackagingJar
Java Version8
Dependencies一旦無し(必要な時に理解しながら追加していく)
[adsense-responsive]

ダウンロードしたzipを展開して、apiというフォルダ名に変更して作業ディレクトリに移動しました。

確認

まずはこの状態でapiフォルダにディレクトリに入って以下のコマンドで動作確認をしてみましょう。

./gradlew bootrun
> Task :bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)

2019-04-01 17:35:35.376  INFO 43476 --- [           main] t.b.service.account.AccountApplication   : Starting AccountApplication on xxx.xxx.xxx.xxx.static.zoot.jp with PID XXXXX (/Users/blogenist/develop/git/github/service-account/api/build/classes/java/main started by blogenist in /Users/blogenist/develop/git/github/service-account/api)
2019-04-01 17:35:35.381  INFO 43476 --- [           main] t.b.service.account.AccountApplication   : No active profile set, falling back to default profiles: default
2019-04-01 17:35:36.854  INFO 43476 --- [           main] t.b.service.account.AccountApplication   : Started AccountApplication in 2.342 seconds (JVM running for 3.301)

BUILD SUCCESSFUL in 32s
3 actionable tasks: 3 executed

正しくビルド及び実行が出来ましたね。

devtoolsプロジェクトの作成

では、次にdevtoolsのプロジェクトを作りましょう。

apiプロジェクト内部で各コマンドを行っても良いですが、筆者の好みとしてapiプロジェクトはapiの事だけに専念してもらって、開発における操作をするためのdevtoolsプロジェクトを作るようにしています。

ローカル開発でのコマンドやFlywayなどを使ったマイグレーとなどもdevtoolsプロジェクトにてシェルなどにして管理すれば、開発スピードも上がるし、ファイルが混在するのも避けれますしね♪

まずは作業ディレクトリに移動して、cp -R api devtoolsコマンドでapiディレクトリをdevtoolsとして再帰的にコピーしましょう。

コピーが出来たら、まずapiディレクトリからは以下のファイルを削除します。

apiディレクトリで削除するファイル
  • gradleディレクトリ
  • gradlew
  • gradlew.bat
  • settings.gradle

次は、devtoolsディレクトリからは以下のファイルを削除します。

devtoolsディレクトリで削除するファイル
  • srcディレクトリ
  • gradlew
  • gradlew.bat
[adsense-responsive]

次に、api/build.gradleの内容を以下のように変更してください。

api/build.gradle
springBoot {
	mainClassName = 'xxx.yyy.zzz.XXXApplication'
}

repositories {
}

dependencies {
}

次に、devtools/settings.gradleを以下のようにしてください。

devtools/settings.gradle
pluginManagement {
	repositories {
		gradlePluginPortal()
	}
}
rootProject.name = 'devtools' //書き換え

includeFlat 'api' // 追加

そして、最後にdevtools/build.gradleの内容を以下のように変更してください。

devtools/build.gradle
buildscript {
    ext {
        springBootVersion = "2.1.3.RELEASE"
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}
allprojects {
}
subprojects {
	apply plugin: "java"
	apply plugin: "org.springframework.boot"
	apply plugin: "io.spring.dependency-management"

	group = 'xxx.yyy.zzz'
	version = '0.0.1-SNAPSHOT'
	sourceCompatibility = '1.8'

	repositories {
		mavenCentral()
	}

	dependencies {
		implementation 'org.springframework.boot:spring-boot-starter'
		testImplementation 'org.springframework.boot:spring-boot-starter-test'
	}

}

確認

では、この状態でdevtoolsディレクトリに移動し、もう一度アプリケーションを実行してみましょう。

./gradlew bootrun
> Task :api:bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)

2019-04-01 18:37:16.982  INFO 47670 --- [           main] t.b.service.account.AccountApplication   : Starting AccountApplication on xxx.xxx.xxx.xxx.static.zoot.jp with PID XXXXX (/Users/blogenist/develop/git/github/service-account/api/build/classes/java/main started by blogenist in /Users/blogenist/develop/git/github/service-account/api)
2019-04-01 18:37:16.986  INFO 47670 --- [           main] t.b.service.account.AccountApplication   : No active profile set, falling back to default profiles: default
2019-04-01 18:37:17.734  INFO 47670 --- [           main] t.b.service.account.AccountApplication   : Started AccountApplication in 1.154 seconds (JVM running for 1.592)

BUILD SUCCESSFUL in 2s
3 actionable tasks: 1 executed, 2 up-to-date

Task :api:bootRunとなっているため、正常にdevtoolsプロジェクトからapiプロジェクトのアプリケーションを起動出来るようになりましたね♪

gradleプロパティ値の外部ファイル化

システムを開発していると、依存関係のあるライブラリやビルド情報などの設定値を設けるようになります。

[adsense-responsive]

これらの値をdevtools/build.gradleに直接定義しても良いのですが、せっかくなので設定値のみをまとめたプロパティファイルを用意してそちらから読み込むようにしてみましょう。

まず、devtoolsプロジェクトにproperty.gradleを作成しましょう。

devtools/property.gradle
ext {
    accountService = [:]
    accountService.springBootVersion = '2.1.3.RELEASE'
    accountService.sourceCompatibility = 1.8
    accountService.group = 'xxx.yyy.zzz'
    accountService.version = '0.0.1-SNAPSHOT'
}

これは、Groovyの書き方で、空の連想配列を用意した上で各キーに対して設定値を定義している形になります。

そして、devtools/build.gradleを以下のように修正します。

devtools/build.gradle
buildscript {
	apply from: 'property.gradle' // プロパティファイルの読み込み
  ext { //定義不要になる
  }
  repositories {
      mavenCentral()
  }
  dependencies {
      classpath("org.springframework.boot:spring-boot-gradle-plugin:${accountService.springBootVersion}") // 読み込んだ変数を展開
  }
}
allprojects {
	apply plugin: 'eclipse'
}
subprojects {
	apply plugin: "java"
	apply plugin: "org.springframework.boot"
	apply plugin: "io.spring.dependency-management"

	group = accountService.group// 読み込んだ変数を展開
	version = accountService.version// 読み込んだ変数を展開
	sourceCompatibility = accountService.sourceCompatibility// 読み込んだ変数を展開

	repositories {
		mavenCentral()
	}

	dependencies {
		implementation "org.springframework.boot:spring-boot-starter:${accountService.springBootVersion}"// マシン毎のバージョン差異が出ないように指定追加
		testImplementation "org.springframework.boot:spring-boot-starter-test:${accountService.springBootVersion}"// マシン毎のバージョン差異が出ないように指定追加
	}

}

確認

ではもう一度確認してみましょう。

./gradlew bootrun
> Task :api:bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)

2019-04-01 18:51:29.148  INFO 48393 --- [           main] t.b.service.account.AccountApplication   : Starting AccountApplication on xxx.xxx.xxx.xxx.static.zoot.jp with PID 48393 (/Users/blogenist/develop/git/github/service-account/api/build/classes/java/main started by blogenist in /Users/blogenist/develop/git/github/service-account/api)
2019-04-01 18:51:29.151  INFO 48393 --- [           main] t.b.service.account.AccountApplication   : No active profile set, falling back to default profiles: default
2019-04-01 18:51:29.958  INFO 48393 --- [           main] t.b.service.account.AccountApplication   : Started AccountApplication in 1.205 seconds (JVM running for 1.628)

BUILD SUCCESSFUL in 2s
3 actionable tasks: 1 executed, 2 up-to-date

こちらも問題なく動きましたね。

アプリケーションプロパティファイルの整理

次に、アプリケーションプロパティファイルを整理しましょう。

デフォルトではapi/src/main/resrouces/application.propertiesが用意されています。

もちろん、このままでもよいのですがSpringBootはyml形式のプロパティファイルをサポートしています。

xml形式より格段に可読性が高く記述方法が簡単なのでyml形式がオススメです!

また、本番/検証/開発/ローカルごとに接続情報等は変わるので、その辺にも対応出来るような構造にしておきましょう。

まずは、application.propertiesapplication.ymlにリネームして、以下の記述を追記してください。

[adsense-responsive]

また、環境ごとに差分がない設定値を定義するためのapplication-common.ymlを用意してください。
今回の作業では特に内容は指定しませんが、今後こちらにも定義をしていこうと思っています。

src/main/resources/application.yml
#profileの指定が無い場合のデフォルトのprofile指定
spring:
  profiles:
    active: local
    include: common

これはプロファイル指定を忘れた際に間違えて開発や検証、本番に向き先が行く事故を防ぐための設定となります。

次に、api/src/main/resourcesディレクトリにapplication-local.ymlapplication-local.yml.tmpを作成します。

Springでは、application-{profile名}.ymlを用意しておく事でそれぞれの環境にあったプロパティファイルを読み込んでくれます。

また、ローカル用のprofileに関しては設定が異なると思うので、application-local.yml.tmpをgit管理して、各自はそれをapplication-local.ymlリネームコピーして設定を変えるようにしています。
ファイルの中身は一旦は空で良いです。

確認(profile未指定)

ではもう一度確認してみましょう。

./gradlew bootrun
> Task :api:bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)

2019-04-01 18:57:39.148  INFO 48393 --- [           main] t.b.service.account.AccountApplication   : Starting AccountApplication on xxx.xxx.xxx.xxx.static.zoot.jp with PID 48393 (/Users/blogenist/develop/git/github/service-account/api/build/classes/java/main started by blogenist in /Users/blogenist/develop/git/github/service-account/api)
2019-04-01 18:57:39.151  INFO 48393 --- [           main] t.b.service.account.AccountApplication   : The following profiles are active: common,local
2019-04-01 18:57:39.958  INFO 48393 --- [           main] t.b.service.account.AccountApplication   : Started AccountApplication in 1.205 seconds (JVM running for 1.628)

BUILD SUCCESSFUL in 2s
3 actionable tasks: 1 executed, 2 up-to-date

ログにThe following profiles are active: localと出ているので、未指定時はデフォルトのプロパティファイルに指定したlocalが適用されるようになりましたね♪

確認

上記で未指定時にはデフォルトのlocalが適用されるようになりましたが、本来はデプロイミス等を防ぐために、意図してprofileを指定する癖をつけておいたほうが良いでしょう。

実行時に-Pargs="--spring.profiles.active={profile名}"をつける事でプロファイルを指定する事が可能になります。

以下のコマンドで確認しましょう。

./gradlew bootrun -Pargs=
> Task :api:bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)

2019-04-03 15:20:17.595  INFO 34962 --- [           main] t.b.service.account.AccountApplication   : Starting AccountApplication on xxx.xxx.xxx.xxx.static.zoot.jp with PID 34962 (/Users/blogenist/develop/git/github/service-account/api/build/classes/java/main started by blogenist in /Users/blogenist/develop/git/github/service-account/api)
2019-04-03 15:20:17.599  INFO 34962 --- [           main] t.b.service.account.AccountApplication   : The following profiles are active: common,local
2019-04-03 15:20:18.439  INFO 34962 --- [           main] t.b.service.account.AccountApplication   : Started AccountApplication in 1.804 seconds (JVM running for 2.488)

BUILD SUCCESSFUL in 3s
3 actionable tasks: 1 executed, 2 up-to-date

以上のように、問題なくprofile指定がlocalに有効な状態で起動出来ましたね♪

ちなみに、hogeのような存在しないprofileを指定するとエラーにならずにデフォルトのprofileが読み込まれます。
今回の場合は内部的にはlocalが適用されます。

起動用シェルの作成

最後に、ローカル開発用の起動用ファイルを作成しましょう。

devtoolsプロジェクトにapiディレクトリを作成し、その中にbootrun.shと言うファイルを作成します。
中身は単純で、ディレクトリ移動して先ほど打っていたコマンドを実行するだけのものです。

devtools/api/bootrun.sh
#!/bin/bash

pushd ../
./gradlew bootRun  -Pargs="--spring.profiles.active=local"
popd

確認

では、実際に起動用シェルからアプリケーションを動かしてみましょう。

sh ./bootrun.sh
~/develop/git/github/service-account/devtools ~/develop/git/github/service-account/devtools/api

> Task :api:bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)

2019-04-01 19:02:04.487  INFO 48649 --- [           main] t.b.service.account.AccountApplication   : Starting AccountApplication on xxx.xxx.xxx.xxx.static.zoot.jp with PID 48649 (/Users/blogenist/develop/git/github/service-account/api/build/classes/java/main started by blogenist in /Users/blogenist/develop/git/github/service-account/api)
2019-04-01 19:02:04.490  INFO 48649 --- [           main] t.b.service.account.AccountApplication   : The following profiles are active: common,local
2019-04-01 19:02:05.171  INFO 48649 --- [           main] t.b.service.account.AccountApplication   : Started AccountApplication in 1.088 seconds (JVM running for 1.489)

BUILD SUCCESSFUL in 2s
3 actionable tasks: 1 executed, 2 up-to-date
~/develop/git/github/service-account/devtools/api

無事に起動シェル経由でprofileがlocalの状態で動きましたね♪

完成ディレクトリ構造

最終的にはこのようなディレクトリ構造になりました。

[adsense-responsive]

tree
.
├── README.md
├── api
│   ├── build
│   ├── build.gradle
│   └── src
│       ├── main
│       │   ├── java
│       │   │   └── tech
│       │   │       └── blogenist
│       │   │           └── service
│       │   │               └── account
│       │   │                   └── AccountApplication.java
│       │   └── resources
│       │       ├── application-common.yml
│       │       ├── application-develop.yml
│       │       ├── application-local.yml
│       │       ├── application-local.yml.tmp
│       │       ├── application-production.yml
│       │       ├── application-staging.yml
│       │       └── application.yml
│       └── test
│           └── java
│               └── tech
│                   └── blogenist
│                       └── service
│                           └── account
│                               └── AccountApplicationTests.java
└── devtools
    ├── api
    │   └── bootrun.sh
    ├── build
    │   ├── classes
    │   │   └── java
    │   ├── generated
    │   │   └── sources
    │   │       └── annotationProcessor
    │   │           └── java
    │   ├── resources
    │   └── tmp
    │       └── compileJava
    ├── build.gradle
    ├── gradle
    │   └── wrapper
    │       ├── gradle-wrapper.jar
    │       └── gradle-wrapper.properties
    ├── gradlew
    ├── gradlew.bat
    ├── property.gradle
    └── settings.gradle

終わりに

これでSpring Boot2 + Gradleでのマルチプロジェクトの土台が出来ました。

次は実際にAPIとして動くように手を加えていこうと思います♪