Gradle の使い方

Spring Framework を仕事でする必要があり、その時に、使えるビルドのシステムとして、Maven や Gradle があり、今回は Gradle を選択してみた。Java は相当久しぶりなこともあり、Javaそのものというより、Gradleがよく分かってないことが分かったので、地道にチュートリアルを実施したり、公式のドキュメントを読んだりしてみたので自分のメモとして、書き残してみたい。

# 目的

今回の目的は、Spring Boot の REST-API のプロジェクトに置いて、次のことが出来ること。

* プロジェクトの雛形を作る
* ビルドを実施する
* パスの通った場所に設定ファイル (XML ファイル) を置く必要があり、そのファイルを、設定ファイルのパスの通ったところにコピーすること。jar になる場合は、Jar に含めること。

# リソース

* [Building a RESTful Web Service with Spring Boot Actuator](https://spring.io/guides/gs/actuator-service/)
* [Building Java Projects with Gradle](https://spring.io/guides/gs/gradle/)

# 1. Gradle のインストール

Mac の場合は、Brewで入る。Windows の場合は、公式では、ダウンロードしてパスを通すことになっているが、Chocoratelyでも良い様子。

_Mac_

```
brew install gradle
```

_Windows_

```
choco install gradle
```

ちなみに、Gradle では、[Gradle Wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html)というものがあり、利用者の人が、Gradle をインストールしなくても、自動的にダウンロードして設定をしてくれるWrapperを作成することができる。それを使えば利用だけだとインストールはしなくても良い。

# 2. プロジェクトの雛形を作る

## 2.1. ディレクトリの作成

雛形の作成は、`build.gradle` ファイルを作るところから始まる。Spring Boot の場合は、ソースをおくディレクトリを作る。例えば次のものを作る。`-p` は、ディレクトリなければ作成するオプション。

```
mkdir -p src/main/java/hello
```

## 2.2. ビルドファイルの作成

ゼロから作る場合は、`gradle init` でいくつかのテンプレートが用意されている。Spring Boot の場合は、公式にある雛形からスタートするのが良さげ。

_build.gradle_ 

```gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

bootJar {
    baseName = 'gs-actuator-service'
    version =  '0.1.0'
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-actuator")
    testCompile("org.springframework.boot:spring-boot-starter-test")
    testCompile("junit:junit")
}
```

各パーツを解説してみる。

### 2.2.1. ビルドスクリプトの依存ライブラリの記述

プロジェクトではなく、`build.gradle` 自体に必要なライブラリの記述。ここでは、Mavenのライブラリを指定して、`spring-boot-gradle-plugin`を依存に追加しているのがわかる。

```gradle
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE")
    }
}
```

### 2.2.2. plugin

`build.gradle` は Groovyの形式で書かれている。ちなみに、Kotlin の形式でもかける様子。基本的な挙動としては、Taskというスクリプトの実行単位があ理、実態はJavaのクラスになっている。そのDSLがこのファイルだ。そのTaskを実行したり、その依存関係を定義したりして使うようになっている。
　`plugin` は、先に誰かが作ったタスクの集まりを利用するためのもの。

```gradle
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

```
### 2.2.3. 起動可能なJarの定義

こちらに説明があるが、`java -jar xxx` の形式でサーバーが立ち上がる jar を作成することができる。このコンフィグレーションが[BootJar](https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/gradle-plugin/api/org/springframework/boot/gradle/tasks/bundling/BootJar.html)を見ればわかる。ここでは、jar の名前と、バージョンを指定している。これ以外にもパッケージングに関する設定が可能になっている。

[Spring Boot Gradle Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/)


```gradle
bootJar {
    baseName = 'gs-actuator-service'
    version =  '0.1.0'
}
```
チュートリアルにある雛形はこれで、これで、REST API を作るための Spring Boot のビルドファイルが出来ている。

### 2.2.4. その他のプロパティ

`sourceCompatibility` は、JavaをコンパイルするときのJavaのバージョン
`targetCompatibility` は、どのバージョンのクラスを作成するかの指定

おそらく、Javaは、古いバージョンのクラスファイルを作成できるのかもしれない。通常は同じでよい。

* [JavaPlugin - Other convention prperties](https://docs.gradle.org/current/userguide/java_plugin.html)


```gradle
sourceCompatibility = 1.8
targetCompatibility = 1.8
```

### 2.2.5. プロジェクトの依存関係

先ほどは、スクリプト自体だったが、こちらは、プロジェクトに必要な依存関係を追加する場所。自分のプロジェクトに、ライブラリを追加したいときは、こちら。`buildscript` の方に追加しても、プロジェクトの方は依存関係にならないので注意。　

```gradle
repositories {
    mavenCentral()
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-actuator")
    testCompile("org.springframework.boot:spring-boot-starter-test")
    testCompile("junit:junit")
}
```

#### 2.2.6. 設定ファイルをクラスパスが有効な場所に移動する

ビルドをするときに、クラスパス上に置く必要のあるxmlファイルがあり、それがビルド時にコピーされる必要があったので調べてみた。こういうエントリを追加すると、`resources`ディレクトリの下にxmlファイルがコピーされる。ちなみに、これは、Jarファイルになったときには、Jarファイルのクラスパスの下に置かれる。

```gradle
sourceSets.main.resources {
    srcDirs = ['src/main/java']
    include '**/*.xml'
}
```

ここで、[Resources](https://docs.gradle.org/current/userguide/java_plugin.html#resources) ディレクトリはどういうものだろうか？Javaプラグインで定義されており、XMLのプロパティファイルのような、プロダクションリソースを置く場所。デフォルトが決まっているが、[Source sets](https://docs.gradle.org/current/userguide/java_plugin.html#source_sets)を書き換えることで変更可能になる。デフォルトは `[src/$name/resources]`。


## 2.3. 各種のコマンド

この状態で、コードを作成すれば、ビルドが出来る状態になるが、他にも便利なコマンドをみていこう。

### 2.3.1. ビルドする

```
gradle build
```

### 2.3.2. Gradle Wrapper を作る

使う人がGradleをインストールしなくても使えるようにGradleWrapperを作る

```
gradle wrapper --gradle-version 5.0
```

これで次回から`gradlew` コマンドが使えるようになる。これによりユーザーのGradleのインストールが不要になる。

```
gradlew build
```

### 2.3.3. Spring Boot の実行

Spring boot を実行する場合は

```
gradle bootRun
```

でよい。もしくはつまり、ビルドした jar ファイルを実行してやれば良い。

```
gradle build
java -jar build/libs/gs-actuator-service-0.1.0.jar
```

### 2.3.4. 使えるタスクを調べる

`gradle tasks` で現在使えるタスクのリファレンスができる


```
$ gradle tasks
Starting a Gradle Daemon (subsequent builds will be faster)

> Task :tasks

------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------

Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.

Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'libs'.
components - Displays the components produced by root project 'libs'. [incubating]
dependencies - Displays all dependencies declared in root project 'libs'.
dependencyInsight - Displays the insight into a specific dependency in root project 'libs'.
dependentComponents - Displays the dependent components of components in root project 'libs'. [incubating]
help - Displays a help message.
model - Displays the configuration model of root project 'libs'. [incubating]
projects - Displays the sub-projects of root project 'libs'.
properties - Displays the properties of root project 'libs'.
tasks - Displays the tasks runnable from root project 'libs'.

To see all tasks and more detail, run gradle tasks --all

To see more detail about a task, run gradle help --task <task>

BUILD SUCCESSFUL in 5s
1 actionable task: 1 executed
```

### 2.3.5 ビルドの分析

なんとグラフィカルに、タスクを分析することが出来ます。

<img width="1232" alt="Screen Shot 2019-01-01 at 12.07.06 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/50103e2a-b3fc-4593-a3b1-b6a4c43cef67.png">


```
gradle taskname --scan
```

### 2.4. カスタムタスク

多くは説明しないが、Javaで出来ているので、カスタムタスクは単なるクラスだ。既存のクラスを組み合わせる場合は、特にクラスを作成する必要もない。これは、先のオペレーションを手動でしようともがいてたときの例。コピータスクを作成して、強引にbuildタスク実行時に実行しようとしている（ただし、この設定だと、このタスクでコピーしたのち、buildタスクがクリーンアップしてコピーしていると思われ、該当のファイルは消えます。

```gradle
task copy(type:Copy) {
     description 'Copies ApplicationInsights.xml to the class path dir'
     from file('src/main/java/ApplicationInsights.xml')
     into file('$buildDir/classes/java/main')
}

build.dependsOn copy
```
詳細は下記まで。

* [Authoring Tasks](https://docs.gradle.org/current/userguide/more_about_tasks.html)

# まとめ

表面的ではあるが、これで一通り、なんとかGradleを使い始められるようにはなったのでよしとしよう。