背景
JavaでSpringBootを触る機会は多かったのですが、
Spring Initializr もKotlinが選択できるようになっているし、
いつかはKotlinで書いてみるつもりでした。
やってみたらKotlin云々よりもマルチモジュールのgradleの書き方で
少しハマったので備忘として残しておきます。
Gradle Kotlin DSL とは
GradleのビルドスクリプトをKotlinで書けるようになります。
詳しくはこのあたりを参照。
Spring Initializrでプロジェクト作ると最初からKotlin DSLで書かれています。
バージョン
software | version |
---|---|
Spring Boot | 2.4.1 |
JDK | Corretto-11.0.9.12.1 |
Kotlin | 1.4.21 |
Gradle | 6.7.1 |
マルチモジュール構成
以下のようなWebとBatchがCoreを参照するマルチモジュールとする。
.
├── build.gradle.kts
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── practice-batch
│ ├── build.gradle.kts
│ └── src
│ ├── main
│ │ ├── kotlin
│ │ │ └── com
│ │ │ └── example
│ │ │ └── practice
│ │ │ └── batch
│ │ │ └── PracticeBatchApplication.kt
│ │ └── resources
│ │ └── application.yml
│ └── test
│ └── kotlin
│ └── com
│ └── example
│ └── practice
│ └── batch
│ └── PracticeBatchApplicationTests.kt
├── practice-core
│ ├── build.gradle.kts
│ └── src
│ ├── main
│ │ └── kotlin
│ └── test
│ ├── kotlin
│ │ └── com
│ │ └── example
│ │ └── practice
│ │ └── core
│ │ ├── PracticeCoreApplication.kt
│ │ └── PracticeCoreApplicationTests.kt
│ └── resources
│ └── application.yml
├── practice-web
│ ├── backend
│ │ └── src
│ │ ├── main
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── practice
│ │ │ │ └── web
│ │ │ │ └── PracticeWebApplication.kt
│ │ │ └── resources
│ │ │ └── application.yml
│ │ └── test
│ │ └── kotlin
│ │ └── com
│ │ └── example
│ │ └── practice
│ │ └── web
│ │ └── PracticeWebApplicationTests.kt
│ └── build.gradle.kts
└── settings.gradle.kts
ビルドスクリプト
build.gradle.kts
ルートプロジェクトのビルドスクリプト。
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.springframework.boot.gradle.plugin.SpringBootPlugin
import org.springframework.boot.gradle.tasks.bundling.BootJar
plugins {
id("java")
id("org.springframework.boot") version "2.4.1"
id("io.spring.dependency-management") version "1.0.10.RELEASE"
kotlin("jvm") version "1.4.21"
kotlin("plugin.spring") version "1.4.21"
}
tasks.getByName<BootJar>("bootJar") {
enabled = false // ルートプロジェクトで実行Jarを作成しない設定
}
tasks.getByName<Jar>("jar") {
enabled = false // ルートプロジェクトでJarを作成しない設定
}
allprojects {
repositories {
mavenCentral()
}
}
subprojects {
group = "com.example"
version = "0.0.1-SNAPSHOT"
apply(plugin = "kotlin")
apply(plugin = "org.jetbrains.kotlin.plugin.spring")
apply(plugin = "io.spring.dependency-management")
dependencyManagement {
imports {
mavenBom(SpringBootPlugin.BOM_COORDINATES)
}
}
java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
}
dependencies {
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
// 以下、JUnit5の設定を入れておく
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude("junit")
}
testImplementation("org.junit.jupiter:junit-jupiter-api")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "11"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
}
setting.gradle.kts
rootProject.name = "practice-parent"
include(":practice-core")
include(":practice-batch")
include(":practice-web")
include(":practice-web:backend")
practice-core/build.gradle.kts
SpringBootのコンポーネントを実装できる共通的なライブラリプロジェクトのビルドスクリプト。
import org.springframework.boot.gradle.tasks.bundling.BootJar
apply(plugin = "org.springframework.boot")
apply(plugin = "io.spring.dependency-management")
dependencies {
implementation("org.springframework.boot:spring-boot-starter")
}
tasks.getByName<BootJar>("bootJar") {
enabled = false // practice-coreで実行Jarを作成しない設定
}
tasks.getByName<Jar>("jar") {
enabled = true
}
practice-web/build.gradle.kts
配下に複数のモジュールがある場合は作っておいても良いかも。
tasks.getByName<Jar>("jar") {
enabled = false
}
practice-web/backend/build.gradle.kts
practice-coreに依存するWebプロジェクトのビルドスクリプト。
import org.springframework.boot.gradle.tasks.bundling.BootJar
apply(plugin = "org.springframework.boot")
apply(plugin = "io.spring.dependency-management")
dependencies {
implementation(project(":practice-core"))
implementation("org.springframework.boot:spring-boot-starter-web")
}
tasks.getByName<BootJar>("bootJar") {
// 実行Jar用のMainクラスを設定する
mainClass.set("com.example.practice.web.PracticeWebApplication")
}
practice-batch/build.gradle.kts
practice-coreに依存するBatchプロジェクトのビルドスクリプト
import org.springframework.boot.gradle.tasks.bundling.BootJar
apply(plugin = "org.springframework.boot")
apply(plugin = "io.spring.dependency-management")
dependencies {
implementation(project(":practice-core"))
implementation("org.springframework.boot:spring-boot-starter")
}
tasks.getByName<BootJar>("bootJar") {
// 実行Jar用のMainクラスを設定する
mainClass.set("com.example.practice.batch.PracticeBatchApplication")
}
コード
practice-core/src/test/・・・/PracticeCoreApplication.kt
ライブラリプロジェクトなのでsrc/main配下にはメインメソッドを持つクラスは不要。
SpringBootTestを実施できるようにsrc/test配下にメインメソッドを持つクラスを配置する。
メインメソッドはSpringInitializrで作成されたものをそのまま利用。
package com.example.practice.core
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class PracticeCoreApplication
fun main(args: Array<String>) {
runApplication<PracticeCoreApplication>(*args)
}
practice-web/src/main/・・・/PracticeWebApplication.kt
SpringBootアプリケーションとして起動するためにsrc/main配下にメインメソッドを持つクラスを配置。
java -jar
で実行できるように、practice-coreとはメインメソッドの書き方を変えている。
package com.example.practice.web
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.ComponentScan
@SpringBootApplication
@ComponentScan("com.example.practice")
class PracticeWebApplication {
companion object {
@JvmStatic fun main(args: Array<String>) {
runApplication<PracticeWebApplication>(*args)
}
}
}
practice-batch/src/main/・・・/PracticeBatchApplication.kt
PracticeWebApplicationと同様のため割愛。
まとめ
とりあえずこれでビルドできました。
マルチモジュールのスタートラインとしては十分だと思います。
以上です。