LoginSignup
8
6

More than 3 years have passed since last update.

Spring Boot 2 (Kotlin) + Gradle Kotlin DSL でマルチモジュールを実現してみた

Posted at

背景

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を参照するマルチモジュールとする。
MultiModuleImage.png

.
├── 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と同様のため割愛。

まとめ

とりあえずこれでビルドできました。
マルチモジュールのスタートラインとしては十分だと思います。
以上です。

参考サイト

8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6