GAE SEでJava8+Spring Bootやってみた（あとその開発環境について）


GAE JavaでJava8+Spring Bootをやってみました。
基本は公式サイトをやってれば良いんですがちょいちょい開発環境という点でハマったりしたのでメモ。
というか公式のドキュメントがけっこうバラバラにあってどれを参照するのがいいのかよくわからなかったりして大変でした。

今回はこの[Using Apache Maven and the App Engine Plugin](https://cloud.google.com/appengine/docs/standard/java/tools/maven#java8)をベースに[GitHubのリポジトリ](https://github.com/GoogleCloudPlatform/getting-started-java/tree/master/appengine-standard-java8/springboot-appengine-standard)から内容を拝借しながら作ってみました。


間違ったりこうした方がいいとかあれば遠慮なく編集リクエストよろしくお願いします。

本当はGradle派ですが、Gradleで色々試したけど紆余曲折あって辛くてやめました。
たぶんもうちょいちゃんとやれば大丈夫なはずです。

今回のコードは[Github](https://github.com/shabutora/gae-java8-trial)に置きました。

## 必要なもの

- Java8
- Maven 3.5
- Gcloud SDK
	- AppEngine SDK Java
- IntelliJ IDEA
	- Google Cloud Toolsプラグイン

## アプリケーション作成

Maven Archetypeで作成します。
たぶんこれが一番きれいに作れると思います。

```
mvn archetype:generate -Dappengine-version=1.9.54 \
-Djava8=true \
-DCloudSDK_Tooling=true \
-DuseObjectify=true \
-Dapplication-id=your-app-id \
-Dfilter=com.google.appengine.archetypes:
```

Datastoreを使う場合はObjectifyを推奨されてるみたいなので、`useObjectify`をTrueで指定すれば最初から依存関係に追加してくれます。

ちょっとローディングとか色々やってると以下のような出力になります。

```
[INFO] Generating project in Interactive mode
[INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
Choose archetype:
1: remote -> com.google.appengine.archetypes:appengine-flexible-archetype (A basic Java application with Google App Engine flexible.)
2: remote -> com.google.appengine.archetypes:appengine-skeleton-archetype (A skeleton application with Google App Engine)
3: remote -> com.google.appengine.archetypes:appengine-standard-archetype (A basic Java application with Google App Engine Standard)
4: remote -> com.google.appengine.archetypes:endpoints-skeleton-archetype (A skeleton project using Cloud Endpoints Frameworks with Google App Engine Standard)
5: remote -> com.google.appengine.archetypes:guestbook-archetype (A guestbook application with Google App Engine)
6: remote -> com.google.appengine.archetypes:hello-endpoints-archetype (A simple starter application using Cloud Endpoints Frameworks with Google App Engine Standard)
7: remote -> com.google.appengine.archetypes:skeleton-archetype (Archetype with a README about Google App Engine archetypes)
```

公式の説明を見てもどれを選べば良いのかイマイチ判断が付きかねるのですが、`3`でイイと思います。
Cloud Endpointsを使いたい人は`4`あたりでしょうか。
ちゃんとみてないのでアレですが、違いがObjectifyを作成時に指定できるかどうかとMockitoのバージョンがSkelton(`2`)だと2.0のβになってるくらいの違いでした。
生成されるコードに違いはありません。
というかSpring Bootで動かすので生成されるJavaコードは後で捨てますが。

残りはGroupIDやらArtifactIDやらPackageやら聞かれるので答えていけばOKです。

これでJava8で動くAppEngine SEのソースコードのできあがり。
Hello Worldが入ってるだけですが。

## 開発環境

### IDEAの設定

デフォルトでAppEngineプラグインが入ってるかもしれません。
こちらはDeprecatedになってるので無効にしましょう。

- Google Cloud Toolsプラグインをインストール
- Google App Engineプラグインを無効化

詳細は[こちら](https://cloud.google.com/tools/intellij/docs/migrate)を参照して下さい。

![スクリーンショット 2017-08-29 16.23.17.png](https://qiita-image-store.s3.amazonaws.com/0/8637/149e0bfb-bead-cb6e-3e4d-2626772e8c69.png "スクリーンショット 2017-08-29 16.23.17.png")

組み込まれてるのでアンインストールできないと思うので無効です。
そのうちバージョンアップで消えるんじゃないかなと思います。

その他のCloudSDKやらの設定は公式の方に書かれているのを参照してもらえば良いかなと思います。
![スクリーンショット 2017-08-29 17.12.52.png](https://qiita-image-store.s3.amazonaws.com/0/8637/53c7d76b-1531-69d1-cc4f-c7375536be94.png "スクリーンショット 2017-08-29 17.12.52.png")
![スクリーンショット 2017-08-29 17.12.24.png](https://qiita-image-store.s3.amazonaws.com/0/8637/5a96fe92-00cc-84f2-a3c0-21ea01e37f52.png "スクリーンショット 2017-08-29 17.12.24.png")

![スクリーンショット 2017-08-29 17.18.04.png](https://qiita-image-store.s3.amazonaws.com/0/8637/1ef24bed-c3d8-0b86-f9b2-88742e3bbed8.png "スクリーンショット 2017-08-29 17.18.04.png")


### プロジェクトの作成

適当に空のプロジェクトを作成してください。
そこにImport Moduleします。

プロジェクトのSDKはJava8を指定しておいてください。

![スクリーンショット 2017-08-29 17.13.36.png](https://qiita-image-store.s3.amazonaws.com/0/8637/d381de51-650e-3ba0-5418-d20bff8d2d5f.png "スクリーンショット 2017-08-29 17.13.36.png")

### モジュールの追加

作成したアプリケーションをIntteliJのプロジェクトにインポートします。

![スクリーンショット 2017-08-29 17.13.46.png](https://qiita-image-store.s3.amazonaws.com/0/8637/1576e141-f99e-cbcc-969e-85d9210e26d1.png "スクリーンショット 2017-08-29 17.13.46.png")

pom.xmlを指定してインポートしてください。

![スクリーンショット 2017-08-29 17.15.12.png](https://qiita-image-store.s3.amazonaws.com/0/8637/8f31fa77-8167-a6bc-974c-8202e49e7df9.png "スクリーンショット 2017-08-29 17.15.12.png")

インポートしてProject Structureのウィンドウを閉じるとGAEを勝手に検知して設定するかどうか右下に出てくるのでConfigureしてください。

![スクリーンショット 2017-08-29 17.15.25.png](https://qiita-image-store.s3.amazonaws.com/0/8637/c2b57d99-107c-3b74-0f23-9319b51ada4a.png "スクリーンショット 2017-08-29 17.15.25.png")

そして空気を読んで設定を読み込んでローカルサーバやらデプロイの設定をIntelliJ上で実行できるようにしてくれます。

デプロイについてはこの後Edit Configureでプロジェクトの設定などをしないといけません。

### デプロイの設定

![スクリーンショット 2017-08-29 17.16.11.png](https://qiita-image-store.s3.amazonaws.com/0/8637/607f1ccb-0459-cf29-3a87-e6fcba58ebf8.png "スクリーンショット 2017-08-29 17.16.11.png")

デプロイを選びます。
プレゼントマークみたいなのを選べばOK。

そうすると下にデプロイの設定やらプロジェクトの設定やらが出てきます。

![スクリーンショット_2017-08-29_17_16_35.png](https://qiita-image-store.s3.amazonaws.com/0/8637/681da08a-b277-7121-d0e0-56b3d1fcf2b9.png "スクリーンショット_2017-08-29_17_16_35.png")

初回はログインしないといけないのでボタンをポチるとブラウザが開いてログインします。
認証済みだと画像のような感じで所有しているプロジェクトが出てくるので対象のGCPプロジェクトを選択してください。


デプロイオプション

![スクリーンショット 2017-08-29 17.17.01.png](https://qiita-image-store.s3.amazonaws.com/0/8637/42ced0d4-9ba4-edf2-43a4-590539619860.png "スクリーンショット 2017-08-29 17.17.01.png")

VersionはAuto Generateにしといた方がよさそう。
即トラフィックをデプロイしたバージョンにしたい場合は`Promote the deployed version to receive all traffic`をONにすればいいです。
CronやらIndexやらの更新もあるならUpdateほげほげの所もONにするといいでしょう。

## Spring Bootにしていく

### 依存関係の追加

`pom.xml`をいじりましょう。
AppEngineはJettyらしいので、Spring BootデフォルトのTomcatを除外する必要があります。

`<dependencies>`に追加

```
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring.boot.version}</version>
            <!-- Exclude Tomcat so that it doesn't conflict w/ Jetty server -->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- Exclude any jul-to-slf4j -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jul-to-slf4j</artifactId>
            <scope>provided</scope>
        </dependency>
```

`<dependencyManagement>`を追加

```
    <dependencyManagement>
        <dependencies>
            <dependency>
                <!-- Import dependency management from Spring Boot -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
```

`<plugins>`に追加

```
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring.boot.version}</version>
            </plugin>
```

`<properties>`に追加

```
        <spring.boot.version>1.5.6.RELEASE</spring.boot.version>
```

これで後は普通にSpring Boot Applicationを実装していってください。
アーキタイプで生成されたHelloAppEngineとかindex.jspとかは消してしまっても問題ありません。

### 起動時のバナー出力はOFFにする

Loggingに出るのがウザくなるのでOFFにするのがオススメです。
ONだとこんな感じ。

![スクリーンショット 2017-08-29 17.25.28.png](https://qiita-image-store.s3.amazonaws.com/0/8637/b9e9429b-dbed-1995-98e8-e64ef9e3d6c4.png "スクリーンショット 2017-08-29 17.25.28.png")

`application.yml`に設定追加しましょう。

```
spring:
    main:
        banner-mode: "off"
```

## まとめ

### かんそー

何か普通にSpring Bootで開発できそうな雰囲気です。
正直最初ドキュメントとか読んだりリポジトリのソースコード読んだりしててMavenのタスクとか間違ってたりしたんで何なんだよって思いながら1日ほど費やしましたが、ローカルで開発するならこれでいけるかなと思います。
コマンドで起動するなら`mvn appengine:run`でいけると思います。

またそのうちちゃんとアプリケーション実装してみてもいいかもしれない。

### 起動時間は？

ほとんど依存関係のない今回のソースコードで初回アクセスでスピンアップして動き始めるまでに10秒くらいかかりますね。
これがどうというのは個人的には何とも言えないので各自判断してください。
(起動の時間をLoggingのリクエスト開始からアプリケーション起動ログが終わるところまでで判断したんだけどこれであってるのかな？)
ちゃんとはかる方法誰か教えてください。

依存関係モリモリにしたらたぶん初回起動が恐ろしく遅くなりそうだからありがちなモノリシックアプリケーションには向いてない気がします。

### おまけ

mavenのappengine pluginのデプロイですが、`gcloud app`コマンド使ってるんですね。


### りぽじとり

今回のソースコードは[こちら](https://github.com/shabutora/gae-java8-trial)