Spring はある程度使った経験があるものの Spring Boot はまともに触ったことがありませんでした。公式ドキュメントを見ながら Spring Boot を初めて試してみたメモをスクリーンキャスト風にまとめたメモです。
Spring Boot のバージョンはこの記事時点で最新の 1.3.0.RELEASE です。Mac OS X で作業しています。Getting Started あたりから順にやっていっただけですが、ドキュメントが充実していてよいですね。
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#getting-started
gradle を使ってプロジェクトをセットアップ
まず gradle が入ってなければ入れる。この記事時点で 2.9 が最新。
brew install gradle
build.gradle の例を貼り付けて gradle wrapper
実行。
buildscript {
repositories {
jcenter()
maven { url "http://repo.spring.io/snapshot" }
maven { url "http://repo.spring.io/milestone" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.0.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'spring-boot'
jar {
baseName = 'myproject'
version = '0.0.1-SNAPSHOT'
}
repositories {
jcenter()
maven { url "http://repo.spring.io/snapshot" }
maven { url "http://repo.spring.io/milestone" }
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
testCompile("org.springframework.boot:spring-boot-starter-test")
}
この時点でこんな感じ。
$ tree
.
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat
と、ビルド時間の削減に Gradle Daemon を使ってみたら?と。
BUILD SUCCESSFUL
Total time: 16.058 secs
This build could be faster, please consider using the Gradle Daemon: https://docs.gradle.org/2.9/userguide/gradle_daemon.html
The Gradle Daemon is a background process that does the heavy lifting of running builds, then stays alive between builds waiting for the next build. This allows data and code that is likely to be required in the next build to be kept in memory, ready to go. This dramatically improves the performance of subsequent builds. Enabling the Gradle Daemon is an extremely cheap way to decrease build times.
早速セットアップしてみる。Mac OS では以下のようにする。
touch ~/.gradle/gradle.properties && echo "org.gradle.daemon=true" >> ~/.gradle/gradle.properties
Spring Boot CLI をセットアップ
次にプロトタイプをさくっとつくるのにおすすめとのことなので Spring Boot の CLI を入れてみる。
The Spring Boot CLI is a command line tool that can be used if you want to quickly prototype with Spring
zip をダウンロードして PATH 通すのかーと思ったが、sdkman というもので入れられるらしい。よく知らなかったが、これはかつては RVM / rbenv に影響された Groovy の GVM (Groovy enVironment Manager) というものだったようだ。
http://sdkman.io/
http://qiita.com/saba1024/items/967ee3d8a79440a97336
とりあえずこれでやってみる。
$ curl -s http://get.sdkman.io | bash
Thanks for using...
SSSSSSSSSSSSSSS DDDDDDDDDDDDD KKKKKKKKK KKKKKKK
SS:::::::::::::::SD::::::::::::DDD K:::::::K K:::::K
S:::::SSSSSS::::::SD:::::::::::::::DD K:::::::K K:::::K
S:::::S SSSSSSSDDD:::::DDDDD:::::D K:::::::K K::::::K
S:::::S D:::::D D:::::DKK::::::K K:::::KKK
S:::::S D:::::D D:::::D K:::::K K:::::K
S::::SSSS D:::::D D:::::D K::::::K:::::K
SS::::::SSSSS D:::::D D:::::D K:::::::::::K
SSS::::::::SS D:::::D D:::::D K:::::::::::K
SSSSSS::::S D:::::D D:::::D K::::::K:::::K
S:::::S D:::::D D:::::D K:::::K K:::::K
S:::::S D:::::D D:::::DKK::::::K K:::::KKK
SSSSSSS S:::::SDDD:::::DDDDD:::::D K:::::::K K::::::K
S::::::SSSSSS:::::SD:::::::::::::::DD K:::::::K K:::::K
S:::::::::::::::SS D::::::::::::DDD K:::::::K K:::::K
SSSSSSSSSSSSSSS DDDDDDDDDDDDD KKKKKKKKK KKKKKKK
mmmmmmm mmmmmmm aaaaaaaaaaaaa nnnn nnnnnnnn
mm:::::::m m:::::::mm a::::::::::::a n:::nn::::::::nn
m::::::::::mm::::::::::m aaaaaaaaa:::::an::::::::::::::nn
m::::::::::::::::::::::m a::::ann:::::::::::::::n
m:::::mmm::::::mmm:::::m aaaaaaa:::::a n:::::nnnn:::::n
m::::m m::::m m::::m aa::::::::::::a n::::n n::::n
m::::m m::::m m::::m a::::aaaa::::::a n::::n n::::n
m::::m m::::m m::::ma::::a a:::::a n::::n n::::n
m::::m m::::m m::::ma::::a a:::::a n::::n n::::n
m::::m m::::m m::::ma:::::aaaa::::::a n::::n n::::n
m::::m m::::m m::::m a::::::::::aa:::a n::::n n::::n
mmmmmm mmmmmm mmmmmm aaaaaaaaaa aaaa nnnnnn nnnnnn
Now attempting installation...
Looking for a previous installation of SDKMAN...
Looking for unzip...
Looking for curl...
Looking for sed...
Installing SDKMAN scripts...
Create distribution directories...
Getting available candidates...
Prime the config file...
Download script archive...
Extract script archive...
Install scripts...
Set version to 3.2.4 ...
Attempt update of bash profiles...
Updated existing /Users/seratch/.bash_profile
Created and initialised /Users/seratch/.bashrc
Attempt update of zsh profiles...
Created and initialised /Users/seratch/.zshrc
All done!
Please open a new terminal, or run the following in the existing one:
source "/Users/seratch/.sdkman/bin/sdkman-init.sh"
Then issue the following command:
sdk help
Enjoy!!!
$ source "/Users/seratch/.sdkman/bin/sdkman-init.sh"
$ sdk help
==== BROADCAST =================================================================
* 17/11/15: Gradle 2.9 released on SDKMAN! #gradle
* 16/11/15: Springboot 1.3.0.RELEASE released on SDKMAN! #springboot
* 05/11/15: Vertx 3.1.0 released on SDKMAN! #vertx
================================================================================
Usage: sdk <command> [candidate] [version]
sdk offline <enable|disable>
commands:
install or i <candidate> [version]
uninstall or rm <candidate> <version>
list or ls [candidate]
use or u <candidate> [version]
default or d <candidate> [version]
current or c [candidate]
outdated or o [candidate]
version or v
broadcast or b
help or h
offline <enable|disable>
selfupdate [force]
flush <candidates|broadcast|archives|temp>
candidate : the SDK to install: groovy, scala, grails, akka, etc.
use list command for comprehensive list of candidates
eg: $ sdk list
version : where optional, defaults to latest stable if not provided
eg: $ sdk install groovy
$
ともあれ sdk コマンドが使えるようになったので sdk install
してみる。
$ sdk install springboot
Downloading: springboot 1.3.0.RELEASE
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 9094k 100 9094k 0 0 748k 0 0:00:12 0:00:12 --:--:-- 1088k
Installing: springboot 1.3.0.RELEASE
Done installing!
Do you want springboot 1.3.0.RELEASE to be set as default? (Y/n): y
Setting springboot 1.3.0.RELEASE as default.
$
セットアップできたようだ。
$ spring
usage: spring [--help] [--version]
<command> [<args>]
Available commands are:
run [options] <files> [--] [args]
Run a spring groovy script
test [options] <files> [--] [args]
Run a spring groovy script test
grab
Download a spring groovy script's dependencies to ./repository
jar [options] <jar-name> <files>
Create a self-contained executable jar file from a Spring Groovy script
war [options] <war-name> <files>
Create a self-contained executable war file from a Spring Groovy script
install [options] <coordinates>
Install dependencies to the lib directory
uninstall [options] <coordinates>
Uninstall dependencies from the lib directory
init [options] [location]
Initialize a new project using Spring Initialzr (start.spring.io)
shell
Start a nested shell
Common options:
-d, --debug Verbose mode
Print additional status information for the command you are running
See 'spring help <command>' for more information on a specific command.
ところで sdkman の BROADCAST というお知らせ欄?に「gradle やら vert.x やらがリリースされているよ!」と出ていたが、他に何があるのか sdk list
で一覧を見ると以下のような感じ。
================================================================================
Available Candidates
================================================================================
q-quit /-search down
j-down ?-search up
k-up h-help
--------------------------------------------------------------------------------
AsciidoctorJ (1.5.2) http://asciidoctor.org/
AsciidoctorJ is the official library for running Asciidoctor on the JVM. Using
AsciidoctorJ, you can convert AsciiDoc content or analyze the structure of a
parsed AsciiDoc document from Java and other JVM languages.
$ sdk install asciidoctorj
--------------------------------------------------------------------------------
Ceylon (1.2.0) http://ceylon-lang.org/
Ceylon is a modern, modular, statically typed programming language for the Java
and JavaScript virtual machines. The language features a flexible and very
readable syntax, a unique and uncommonly elegant static type system, a powerful
module architecture, and excellent tooling.
$ sdk install ceylon
--------------------------------------------------------------------------------
CRaSH (1.3.0) http://www.crashub.org/
The Common Reusable SHell (CRaSH) deploys in a Java runtime and provides
interactions with the JVM. Commands are written in Groovy or Java and can be
developed at runtime making the extension of the shell very easy with fast
development cycle.
$ sdk install crash
--------------------------------------------------------------------------------
Gaiden (1.0) http://kobo.github.io/gaiden/
Gaiden is a tool that makes it easy to create documentation with Markdown.
$ sdk install gaiden
--------------------------------------------------------------------------------
Glide (0.3.3) http://glide-gae.appspot.com/
Glide makes it incredibly easy to develop apps that harness the power of Google
App Engine for Java using expressiveness of Groovy and sweetness of Gaelyk's
syntactic sugar.
$ sdk install glide
--------------------------------------------------------------------------------
Gradle (2.9) http://gradle.org/
Gradle is a build automation tool that builds upon the concepts of Apache Ant
and Apache Maven and introduces a Groovy-based domain-specific language (DSL)
instead of the more traditional XML form of declaring the project
configuration. Gradle uses a directed acyclic graph (DAG) to determine the
order in which tasks can be run.
$ sdk install gradle
--------------------------------------------------------------------------------
Grails (3.0.9) https://grails.org/
Grails is a powerful web framework, for the Java platform aimed at multiplying
developers productivity thanks to a Convention-over-Configuration, sensible
defaults and opinionated APIs. It integrates smoothly with the JVM, allowing
you to be immediately productive whilst providing powerful features, including
integrated ORM, Domain-Specific Languages, runtime and compile-time
meta-programming and Asynchronous programming.
$ sdk install grails
--------------------------------------------------------------------------------
Griffon (1.5.0) http://griffon-framework.org/
Griffon is desktop application development platform for the JVM.Inspired by
Grails, Griffon leverages the use of the Groovy language and concepts like
Convention over Configuration. The Swing toolkit is the default UI toolkit of
choice however others may be used, for example JavaFX.
$ sdk install griffon
--------------------------------------------------------------------------------
Groovy (2.4.5) http://www.groovy-lang.org/
Groovy is a powerful, optionally typed and dynamic language, with static-typing
and static compilation capabilities, for the Java platform aimed at multiplying
developers' productivity thanks to a concise, familiar and easy to learn
syntax. It integrates smoothly with any Java program, and immediately delivers
to your application powerful features, including scripting capabilities,
Domain-Specific Language authoring, runtime and compile-time meta-programming
and functional programming.
$ sdk install groovy
--------------------------------------------------------------------------------
GroovyServ (1.0.0) https://kobo.github.io/groovyserv/
GroovyServ reduces startup time of the JVM for runnning Groovy significantly.
It depends on your environments, but in most cases, it’s 10 to 20 times faster
than regular Groovy.
$ sdk install groovyserv
--------------------------------------------------------------------------------
JBake (2.4.0) http://jbake.org/
JBake is a Java based, open source, static site/blog generator for developers
and designers.
$ sdk install jbake
--------------------------------------------------------------------------------
JBoss Forge (2.17.0.Final) http://forge.jboss.org/
JBoss Forge is the Fastest way to build Maven-based Java EE projects, and
anything else you fancy.
$ sdk install jbossforge
--------------------------------------------------------------------------------
Lazybones (0.8.1) https://github.com/pledbrook/lazybones/
Lazybones allows you to create a new project structure for any framework or
library for which the tool has a template.
$ sdk install lazybones
--------------------------------------------------------------------------------
Maven (3.3.3) https://maven.apache.org/
Apache Maven is a software project management and comprehension tool. Based on
the concept of a project object model (POM), Maven can manage a project's
build, reporting and documentation from a central piece of information.
$ sdk install maven
--------------------------------------------------------------------------------
sbt (0.13.9) http://www.scala-sbt.org/
SBT is an open source build tool for Scala and Java projects, similar to Java's
Maven or Ant. Its main features are: native support for compiling Scala code
and integrating with many Scala test frameworks; build descriptions written in
Scala using a DSL; dependency management using Ivy (which supports Maven-format
repositories); continuous compilation, testing, and deployment; integration
with the Scala interpreter for rapid iteration and debugging; support for mixed
Java/Scala projects
$ sdk install sbt
--------------------------------------------------------------------------------
Scala (2.11.7) http://www.scala-lang.org/
Scala is a programming language for general software applications. Scala has
full support for functional programming and a very strong static type system.
This allows programs written in Scala to be very concise and thus smaller in
size than other general-purpose programming languages. Scala source code is
intended to be compiled to Java bytecode, so that the resulting executable code
runs on a Java virtual machine. Java libraries may be used directly in Scala
code and vice versa. Scala is object-oriented, and uses a curly-brace syntax.
Scala has many features of functional programming languages, including
currying, type inference, immutability, lazy evaluation, and pattern matching.
It also has an advanced type system supporting algebraic data types, covariance
and contravariance, higher-order types, and anonymous types. Other features of
Scala include operator overloading, optional parameters, named parameters, raw
strings, and no checked exceptions.
$ sdk install scala
--------------------------------------------------------------------------------
Spring Boot (1.3.0.RELEASE) http://projects.spring.io/spring-boot/
Spring Boot takes an opinionated view of building production-ready Spring
applications. It favors convention over configuration and is designed to get
you up and running as quickly as possible.
$ sdk install springboot
--------------------------------------------------------------------------------
Vert.x (3.1.0) http://vertx.io/
Vert.x is a tool-kit for building reactive applications on the JVM.
$ sdk install vertx
--------------------------------------------------------------------------------
このラインナップだと使っているもの(Maven、Gradle、sbt、scala)は基本的に全部 Homebrew にあるし、これだけのために sdkman 入れるのは微妙かなと思っていたら、次のセクション「10.2.3 OSX Homebrew installation」で Homebrew でのインストールが紹介されていた。
Homebrew で入れるためにまず sdkman で入れたものを uninstall して
$ sdk uninstall springboot 1.3.0.RELEASE
Unselecting springboot 1.3.0.RELEASE...
Uninstalling springboot 1.3.0.RELEASE...
次に Homebrew で入れ直す。Homebrew の本家にはなく Pivotal の GitHub リポジトリを brew tap
して入れるようだ。
$ brew tap pivotal/tap
$ brew install springboot
Spring Boot CLI のセットアップはこの辺で。
Spring Boot の Web アプリケーションを動かす
「10.2.6 Quick start Spring CLI example」を見ると
@RestController
class ThisWillActuallyRun {
@RequestMapping("/")
String home() {
"Hello World!"
}
}
このような Groovy のコードを app.groovy として保存して spring run app.groovy
とするだけで動くらしい・・マジか。必要最低限の依存ライブラリを Grape で解決するだけでなく import もデフォルトである程度解決されているということなのだろう。
$ spring run app.groovy
Resolving dependencies...........................
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.3.0.RELEASE)
2015-11-23 16:06:26.616 INFO 53470 --- [ runner-0] o.s.boot.SpringApplication : Starting application on seratchs-MacBook-Pro.local with PID 53470 (/Users/seratch/.m2/repository/org/springframework/boot/spring-boot/1.3.0.RELEASE/spring-boot-1.3.0.RELEASE.jar started by seratch in /Users/seratch/Documents/github/spring-boot-example)
2015-11-23 16:06:26.619 INFO 53470 --- [ runner-0] o.s.boot.SpringApplication : No profiles are active
2015-11-23 16:06:27.004 INFO 53470 --- [ runner-0] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@517a4e29: startup date [Mon Nov 23 16:06:27 JST 2015]; root of context hierarchy
2015-11-23 16:06:28.414 INFO 53470 --- [ runner-0] o.s.b.f.s.DefaultListableBeanFactory : Overriding bean definition for bean 'beanNameViewResolver' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2015-11-23 16:06:29.166 INFO 53470 --- [ runner-0] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2015-11-23 16:06:29.181 INFO 53470 --- [ runner-0] o.apache.catalina.core.StandardService : Starting service Tomcat
2015-11-23 16:06:29.183 INFO 53470 --- [ runner-0] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.0.28
2015-11-23 16:06:29.267 INFO 53470 --- [ost-startStop-1] org.apache.catalina.loader.WebappLoader : Unknown loader org.springframework.boot.cli.compiler.ExtendedGroovyClassLoader$DefaultScopeParentClassLoader@6598a08d class org.springframework.boot.cli.compiler.ExtendedGroovyClassLoader$DefaultScopeParentClassLoader
2015-11-23 16:06:29.288 INFO 53470 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2015-11-23 16:06:29.288 INFO 53470 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2284 ms
2015-11-23 16:06:29.754 INFO 53470 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2015-11-23 16:06:29.763 INFO 53470 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2015-11-23 16:06:29.763 INFO 53470 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2015-11-23 16:06:29.764 INFO 53470 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2015-11-23 16:06:29.764 INFO 53470 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2015-11-23 16:06:30.114 INFO 53470 --- [ runner-0] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@517a4e29: startup date [Mon Nov 23 16:06:27 JST 2015]; root of context hierarchy
2015-11-23 16:06:30.200 INFO 53470 --- [ runner-0] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String ThisWillActuallyRun.home()
2015-11-23 16:06:30.203 INFO 53470 --- [ runner-0] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2015-11-23 16:06:30.203 INFO 53470 --- [ runner-0] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2015-11-23 16:06:30.246 INFO 53470 --- [ runner-0] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-11-23 16:06:30.246 INFO 53470 --- [ runner-0] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-11-23 16:06:30.300 INFO 53470 --- [ runner-0] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-11-23 16:06:30.816 INFO 53470 --- [ runner-0] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2015-11-23 16:06:30.921 INFO 53470 --- [ runner-0] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2015-11-23 16:06:30.926 INFO 53470 --- [ runner-0] o.s.boot.SpringApplication : Started application in 4.858 seconds (JVM running for 36.749)
確かに起動した。デフォルトでは Tomcat 8 が起動する様子。localhost:8080 にアクセスすると「Hello World!」というボディで応答が返ってくる。
$ curl -v http://localhost:8080/
* Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 12
< Date: Mon, 23 Nov 2015 07:08:10 GMT
<
* Connection #0 to host localhost left intact
Hello World!$
しばらく特に手を動かすところがないので、ちょっと飛ばして次は「11.3 Writing the code」の Java サンプルを動かしてみる。
mkdir -p src/main/java/
echo 'import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;
@RestController
@EnableAutoConfiguration
public class Example {
@RequestMapping("/")
String home() {
return "Hello World!";
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Example.class, args);
}
}' > src/main/java/Example.java
最初に最低限の Spring Boot プロジェクトを Gradle でセットアップ済だったので、ソースコードを置いて bootRun という Gradle タスクで起動できる。なお Gradle のタスク一覧は tasks で確認できる。
$ ./gradlew tasks
:tasks
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
Application tasks
-----------------
bootRun - Run the project with support for auto-detecting main class and reloading static resources
(以下略)
bootRun は main class の検知と静的ファイルの hot reloading をサポートしているようだ。
./gradlew bootRun
これも全く同じように動作した。
$ curl -v localhost:8080
* Rebuilt URL to: localhost:8080/
* Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 12
< Date: Mon, 23 Nov 2015 07:15:28 GMT
<
* Connection #0 to host localhost left intact
Hello World!$
ここから先のドキュメントは Gradle だけでなく Maven、Ant でのビルド方法や上記で貼り付けた build.gradle についての説明などが続くのでスキップして「III. Using Spring Boot」に入り、「14.2 Locating the main application class」のサンプルを試す。
src/main/java/Example.java
を削除して src/main/java/myproject/Application.java
を追加。とりあえず Example.java で動いていたものをそのまま持ってきて動くようにするとこんな感じになる。
package myproject;
import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.stereotype.*;
import org.springframework.context.annotation.*;
import org.springframework.web.bind.annotation.*;
@Configuration
@EnableAutoConfiguration
@ComponentScan
@RestController // TODO: move
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@RequestMapping("/") String home() { return "Hello World!"; } // TODO: move
}
./gradlew bootRun
を立ち上げ直して、これはこれで動作することを確認する。
次は RestController を分離する。myproject.Application
は main と Spring 全体設定の初期化だけにして
// src/main/java/myproject/Application.java
package myproject;
import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.stereotype.*;
import org.springframework.context.annotation.*;
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
ルーティングや処理メソッドは myproject.web.HomeController
に全て移動。上記のように myproject.Application
に ComponentScan アノテーションを指定しておくと myproject を root package として自動でコンポーネントスキャンされるので、クラスに RestController アノテーションをつけておけば、ルーティング情報が設定されているコンポーネントとして自動で認識してくれる。
// src/main/java/myproject/web/HomeController.java
package myproject.web;
import org.springframework.web.bind.annotation.*;
@RestController
public class HomeController {
@RequestMapping("/") String home() { return "Hello World!"; }
}
./gradlew bootRun
を立ち上げ直して動作確認。
これまで Java コードの変更の度に Gradle を立ち上げ直していたが、hot reloading できるものはないかというと Spring Loaded というものがあるようだ。
https://github.com/spring-projects/spring-loaded
普段関わる Spring のプロジェクトでは JUnit のユニットテストで動作確認していることが多く、Servlet コンテナを自動しっぱなしにして自動的に class を reload しなくてもさほど困らず Spring Loaded は使ったことがなかった(とはいえ、実際不便ではあった)。
このへんの記事を拝見すると簡単に連携できるようなので試してみることに。
http://qiita.com/Sa2/items/c3150e3d43698cd67ff1
また、この辺でそろそろ IDE を使うべきタイミングのようなのでいつものように IntelliJ IDEA を使うことにする。
IntelliJ IDEA + Spring Loaded
まず idea plugin を追加。idea ブロックは IDEA が class ファイルを出力する先を Gralde の出力先と揃えるためとのことでそのままコピペする。
apply plugin: 'idea'
idea {
module {
inheritOutputDirs = false
outputDir = file("$buildDir/classes/main/")
}
}
idea タスクが追加される。
$ ./gradlew tasks
(中略)
IDE tasks
---------
cleanIdea - Cleans IDEA project files (IML, IPR)
idea - Generates IDEA project files (IML, IPR, IWS)
(以下略)
早速実行して IDEA の設定ファイルを出力する。
$ ./gradlew idea
Starting a new Gradle Daemon for this build (subsequent builds will be faster).
:ideaModule
Download https://jcenter.bintray.com/org/springframework/boot/spring-boot-starter-test/1.3.0.RELEASE/spring-boot-starter-test-1.3.0.RELEASE.pom
Download https://jcenter.bintray.com/org/mockito/mockito-core/1.10.19/mockito-core-1.10.19.pom
Download https://jcenter.bintray.com/org/hamcrest/hamcrest-library/1.3/hamcrest-library-1.3.pom
Download https://jcenter.bintray.com/org/springframework/spring-test/4.2.3.RELEASE/spring-test-4.2.3.RELEASE.pom
Download https://jcenter.bintray.com/org/objenesis/objenesis/2.1/objenesis-2.1.pom
Download https://jcenter.bintray.com/org/objenesis/objenesis-parent/2.1/objenesis-parent-2.1.pom
Download https://jcenter.bintray.com/org/springframework/boot/spring-boot-starter-test/1.3.0.RELEASE/spring-boot-starter-test-1.3.0.RELEASE.jar
Download https://jcenter.bintray.com/org/mockito/mockito-core/1.10.19/mockito-core-1.10.19.jar
Download https://jcenter.bintray.com/org/hamcrest/hamcrest-library/1.3/hamcrest-library-1.3.jar
Download https://jcenter.bintray.com/org/springframework/spring-test/4.2.3.RELEASE/spring-test-4.2.3.RELEASE.jar
Download https://jcenter.bintray.com/org/objenesis/objenesis/2.1/objenesis-2.1.jar
Download https://jcenter.bintray.com/org/springframework/boot/spring-boot-starter-web/1.3.0.RELEASE/spring-boot-starter-web-1.3.0.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/springframework/boot/spring-boot-devtools/1.3.0.RELEASE/spring-boot-devtools-1.3.0.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/springframework/boot/spring-boot-starter-test/1.3.0.RELEASE/spring-boot-starter-test-1.3.0.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/springframework/boot/spring-boot-starter/1.3.0.RELEASE/spring-boot-starter-1.3.0.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/springframework/boot/spring-boot-starter-tomcat/1.3.0.RELEASE/spring-boot-starter-tomcat-1.3.0.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/springframework/boot/spring-boot-starter-validation/1.3.0.RELEASE/spring-boot-starter-validation-1.3.0.RELEASE-sources.jar
Download https://jcenter.bintray.com/com/fasterxml/jackson/core/jackson-databind/2.6.3/jackson-databind-2.6.3-sources.jar
Download https://jcenter.bintray.com/org/springframework/spring-web/4.2.3.RELEASE/spring-web-4.2.3.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/springframework/spring-webmvc/4.2.3.RELEASE/spring-webmvc-4.2.3.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/springframework/boot/spring-boot/1.3.0.RELEASE/spring-boot-1.3.0.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/springframework/boot/spring-boot-autoconfigure/1.3.0.RELEASE/spring-boot-autoconfigure-1.3.0.RELEASE-sources.jar
Download https://jcenter.bintray.com/junit/junit/4.12/junit-4.12-sources.jar
Download https://jcenter.bintray.com/org/mockito/mockito-core/1.10.19/mockito-core-1.10.19-sources.jar
Download https://jcenter.bintray.com/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar
Download https://jcenter.bintray.com/org/hamcrest/hamcrest-library/1.3/hamcrest-library-1.3-sources.jar
Download https://jcenter.bintray.com/org/springframework/spring-core/4.2.3.RELEASE/spring-core-4.2.3.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/springframework/spring-test/4.2.3.RELEASE/spring-test-4.2.3.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/springframework/boot/spring-boot-starter-logging/1.3.0.RELEASE/spring-boot-starter-logging-1.3.0.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/yaml/snakeyaml/1.16/snakeyaml-1.16-sources.jar
Download https://jcenter.bintray.com/org/apache/tomcat/embed/tomcat-embed-core/8.0.28/tomcat-embed-core-8.0.28-sources.jar
Download https://jcenter.bintray.com/org/apache/tomcat/embed/tomcat-embed-el/8.0.28/tomcat-embed-el-8.0.28-sources.jar
Download https://jcenter.bintray.com/org/apache/tomcat/embed/tomcat-embed-logging-juli/8.0.28/tomcat-embed-logging-juli-8.0.28-sources.jar
Download https://jcenter.bintray.com/org/apache/tomcat/embed/tomcat-embed-websocket/8.0.28/tomcat-embed-websocket-8.0.28-sources.jar
Download https://jcenter.bintray.com/org/hibernate/hibernate-validator/5.2.2.Final/hibernate-validator-5.2.2.Final-sources.jar
Download https://jcenter.bintray.com/com/fasterxml/jackson/core/jackson-annotations/2.6.3/jackson-annotations-2.6.3-sources.jar
Download https://jcenter.bintray.com/com/fasterxml/jackson/core/jackson-core/2.6.3/jackson-core-2.6.3-sources.jar
Download https://jcenter.bintray.com/org/springframework/spring-aop/4.2.3.RELEASE/spring-aop-4.2.3.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/springframework/spring-beans/4.2.3.RELEASE/spring-beans-4.2.3.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/springframework/spring-context/4.2.3.RELEASE/spring-context-4.2.3.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/springframework/spring-expression/4.2.3.RELEASE/spring-expression-4.2.3.RELEASE-sources.jar
Download https://jcenter.bintray.com/org/objenesis/objenesis/2.1/objenesis-2.1-sources.jar
Download https://jcenter.bintray.com/ch/qos/logback/logback-classic/1.1.3/logback-classic-1.1.3-sources.jar
Download https://jcenter.bintray.com/org/slf4j/jcl-over-slf4j/1.7.13/jcl-over-slf4j-1.7.13-sources.jar
Download https://jcenter.bintray.com/org/slf4j/jul-to-slf4j/1.7.13/jul-to-slf4j-1.7.13-sources.jar
Download https://jcenter.bintray.com/org/slf4j/log4j-over-slf4j/1.7.13/log4j-over-slf4j-1.7.13-sources.jar
Download https://jcenter.bintray.com/javax/validation/validation-api/1.1.0.Final/validation-api-1.1.0.Final-sources.jar
Download https://jcenter.bintray.com/org/jboss/logging/jboss-logging/3.3.0.Final/jboss-logging-3.3.0.Final-sources.jar
Download https://jcenter.bintray.com/com/fasterxml/classmate/1.1.0/classmate-1.1.0-sources.jar
Download https://jcenter.bintray.com/aopalliance/aopalliance/1.0/aopalliance-1.0-sources.jar
Download https://jcenter.bintray.com/ch/qos/logback/logback-core/1.1.3/logback-core-1.1.3-sources.jar
Download https://jcenter.bintray.com/org/slf4j/slf4j-api/1.7.13/slf4j-api-1.7.13-sources.jar
:ideaProject
:ideaWorkspace
:idea
BUILD SUCCESSFUL
Total time: 58.284 secs
この辺は先の qiita 記事の受け売りになるが、IDEA の設定で「Build, Execution, Deloyment」>「Compiler」の「Make project automatically」にチェックを入れた状態で ./gradlew bootRun
を再度立ち上げ。
2015-11-23 19:49:40.575 INFO 56854 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2015-11-23 19:49:40.706 INFO 56854 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2015-11-23 19:49:40.714 INFO 56854 --- [ restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2015-11-23 19:49:40.716 INFO 56854 --- [ restartedMain] myproject.Application : Started Application in 1.015 seconds (JVM running for 54.864)
2015-11-23 19:49:40.801 INFO 56854 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2015-11-23 19:49:40.801 INFO 56854 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2015-11-23 19:49:40.803 INFO 56854 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 2 ms
> Building 80% > :bootRun
この状態で src/main/java/**.java
を変更すると Tomcat を再起動している様子・・
2015-11-23 19:50:15.605 INFO 56854 --- [ Thread-23] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@3e05e4a6: startup date [Mon Nov 23 19:49:39 JST 2015]; root of context hierarchy
2015-11-23 19:50:15.606 INFO 56854 --- [ Thread-23] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.3.0.RELEASE)
2015-11-23 19:50:15.875 INFO 56854 --- [ restartedMain] myproject.Application : Starting Application on seratchs-MacBook-Pro.local with PID 56854 (/Users/seratch/Documents/github/spring-boot-example/build/classes/main started by seratch in /Users/seratch/Documents/github/spring-boot-example)
2015-11-23 19:50:15.875 INFO 56854 --- [ restartedMain] myproject.Application : No profiles are active
2015-11-23 19:50:15.878 INFO 56854 --- [ restartedMain] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@160bf3cd: startup date [Mon Nov 23 19:50:15 JST 2015]; root of context hierarchy
2015-11-23 19:50:16.372 INFO 56854 --- [ restartedMain] o.s.b.f.s.DefaultListableBeanFactory : Overriding bean definition for bean 'beanNameViewResolver' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2015-11-23 19:50:16.524 INFO 56854 --- [ restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2015-11-23 19:50:16.527 INFO 56854 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service Tomcat
2015-11-23 19:50:16.527 INFO 56854 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.0.28
2015-11-23 19:50:16.534 INFO 56854 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2015-11-23 19:50:16.535 INFO 56854 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 657 ms
2015-11-23 19:50:16.615 INFO 56854 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2015-11-23 19:50:16.617 INFO 56854 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2015-11-23 19:50:16.624 INFO 56854 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2015-11-23 19:50:16.624 INFO 56854 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2015-11-23 19:50:16.624 INFO 56854 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2015-11-23 19:50:16.682 INFO 56854 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@160bf3cd: startup date [Mon Nov 23 19:50:15 JST 2015]; root of context hierarchy
2015-11-23 19:50:16.694 INFO 56854 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto java.lang.String myproject.web.HomeController.home()
2015-11-23 19:50:16.696 INFO 56854 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2015-11-23 19:50:16.697 INFO 56854 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2015-11-23 19:50:16.704 INFO 56854 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-11-23 19:50:16.704 INFO 56854 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-11-23 19:50:16.722 INFO 56854 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-11-23 19:50:16.738 INFO 56854 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2015-11-23 19:50:16.794 INFO 56854 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2015-11-23 19:50:16.808 INFO 56854 --- [ restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2015-11-23 19:50:16.809 INFO 56854 --- [ restartedMain] myproject.Application : Started Application in 1.0 seconds (JVM running for 90.958)
2015-11-23 19:50:17.098 INFO 56854 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2015-11-23 19:50:17.098 INFO 56854 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2015-11-23 19:50:17.101 INFO 56854 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 3 ms
Twitter で教えていただいたが、これは Spring Loaded ではなく spring-boot-devtools による挙動だった。
@seratch_ja @megascus それ、Spring Loadedではなく、devtoolsのライブリロードでは?
— Toshiaki Maki (@making) 2015, 11月 23
原因は単に Spring Loaded が追加されていないだけというポカミス。何か変なこと書いてすみません(&ありがとうございます)。
ということで build.gradle の buildscript.dependencies に「classpath("org.springframework:springloaded:1.2.4.RELEASE")」を追加して
buildscript {
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.0.RELEASE")
classpath("org.springframework:springloaded:1.2.4.RELEASE")
}
}
depedencies にある spring-boot-devtools を無効化。
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
//compile("org.springframework.boot:spring-boot-devtools")
testCompile("org.springframework.boot:spring-boot-starter-test")
}
そして Gradle を ./gradlew bootRun
で再起動。
これで、Java コードを書き換えたり、class を追加・移動などしてみると、反映まで少しラグはあるが、再起動せずに hot reloading される。すばらしい。
しかし RequestMapping や Spring に登録されている Bean の情報は hot reloading されないらしく、確かに手元で試してもそういう挙動をしていた。この辺は確かにちょっと不便そうではある。
@seratch_ja コントローラーのURLマッピングとかbean定義とかですねー。
— Σ(・ω・ノ)ノ! (@megascus) 2015, 11月 23
その後、この辺も参考にした。
http://teppeis.hatenablog.com/entry/2015/11/spring-boot-hot-swapping
http://www.bunkei-programmer.net/entry/2015/06/16/012524
あと Spring Loaded が hot reloading したときに何かログは出ないのかな?と思ったが
https://github.com/spring-projects/spring-loaded/wiki/Basic-usage-information
build.gradle に以下を設定するとモリモリとログが出るようになった。
bootRun {
systemProperty("springloaded", "verbose;explain")
}
ファイルを変更してコンパイル結果が出力されると検知して以下のようなログが標準出力に出た。
2015-11-24 12:56:48.262 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.agent.Watcher : Observed last modification time change for /Users/k-sera/Documents/github/spring-boot-example/build/classes/main/myproject/web/HomeController.class (lastScanTime=1448337407162)
2015-11-24 12:56:48.262 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.agent.Watcher : Firing file changed event /Users/k-sera/Documents/github/spring-boot-example/build/classes/main/myproject/web/HomeController.class
2015-11-24 12:56:48.263 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.ReloadableType : Loading new version of myproject/web/HomeController, identifying suffix PUvM9u4, new data length is 593bytes
2015-11-24 12:56:48.264 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=org/springsource/loaded/TypeDiffComputer classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.264 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springsource/loaded/TypeDiffComputer is using a package name 'org/springsource/loaded/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.265 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=sl/org/objectweb/asm/tree/ClassNode classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.266 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=sl/org/objectweb/asm/tree/AnnotationNode classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.267 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=sl/org/objectweb/asm/tree/MethodNode classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.269 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=sl/org/objectweb/asm/tree/InsnList classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.270 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=sl/org/objectweb/asm/tree/LabelNode classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.270 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=sl/org/objectweb/asm/tree/AbstractInsnNode classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.271 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=sl/org/objectweb/asm/tree/LineNumberNode classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.271 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=sl/org/objectweb/asm/tree/VarInsnNode classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.272 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=sl/org/objectweb/asm/tree/MethodInsnNode classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.273 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=sl/org/objectweb/asm/tree/InsnNode classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.273 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=sl/org/objectweb/asm/tree/LocalVariableNode classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.274 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=sl/org/objectweb/asm/tree/LdcInsnNode classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.275 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=org/springsource/loaded/TypeDelta classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.275 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springsource/loaded/TypeDelta is using a package name 'org/springsource/loaded/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.276 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=org/springsource/loaded/MethodDelta classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.276 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springsource/loaded/MethodDelta is using a package name 'org/springsource/loaded/' which is considered infrastructure and types within it are not made reloadable
Reloading: Loading new version of myproject.web.HomeController [PUvM9u4]
2015-11-24 12:56:48.277 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=org/springsource/loaded/CurrentLiveVersion classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.277 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springsource/loaded/CurrentLiveVersion is using a package name 'org/springsource/loaded/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.278 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=org/springsource/loaded/IncrementalTypeDescriptor classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.278 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springsource/loaded/IncrementalTypeDescriptor is using a package name 'org/springsource/loaded/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.279 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=org/springsource/loaded/ExecutorBuilder$ExecutorBuilderVisitor classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.279 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springsource/loaded/ExecutorBuilder$ExecutorBuilderVisitor is using a package name 'org/springsource/loaded/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.280 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=org/springsource/loaded/ExecutorBuilder$ExecutorBuilderVisitor$CopyingAnnotationVisitor classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.280 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springsource/loaded/ExecutorBuilder$ExecutorBuilderVisitor$CopyingAnnotationVisitor is using a package name 'org/springsource/loaded/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.281 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=org/springsource/loaded/ConstructorCopier classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.281 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springsource/loaded/ConstructorCopier is using a package name 'org/springsource/loaded/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.282 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=org/springsource/loaded/MethodCopier classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.282 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springsource/loaded/MethodCopier is using a package name 'org/springsource/loaded/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.283 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=org/springsource/loaded/DispatcherBuilder classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.283 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springsource/loaded/DispatcherBuilder is using a package name 'org/springsource/loaded/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.284 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=org/springsource/loaded/DispatcherBuilder$DispatcherBuilderVisitor classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.284 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springsource/loaded/DispatcherBuilder$DispatcherBuilderVisitor is using a package name 'org/springsource/loaded/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.285 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=myproject/web/HomeController$$DPUvM9u4 classloader=ChildClassLoader typeRegistry=null
2015-11-24 12:56:48.286 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=org/springsource/loaded/__DynamicallyDispatchable classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.286 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springsource/loaded/__DynamicallyDispatchable is using a package name 'org/springsource/loaded/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.286 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=myproject/web/HomeController$$EPUvM9u4 classloader=ChildClassLoader typeRegistry=null
2015-11-24 12:56:48.287 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=java/io/ObjectStreamClass$Caches classloader=null typeRegistry=null
2015-11-24 12:56:48.287 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=com/sun/beans/finder/PropertyEditorFinder classloader=null typeRegistry=null
2015-11-24 12:56:48.288 INFO 40741 --- [Loader@14dad5dc] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=org/springframework/util/ConcurrentReferenceHashMap$2 classloader=Launcher$AppClassLoader typeRegistry=TypeRegistry(id=455659002,loader=sun.misc.Launcher$AppClassLoader)
2015-11-24 12:56:48.288 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springframework/util/ConcurrentReferenceHashMap$2 is using a package name 'org/springframework/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.288 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springframework/util/ConcurrentReferenceHashMap$2 is using a package name 'org/springframework/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.289 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springframework/util/ConcurrentReferenceHashMap$Task is using a package name 'org/springframework/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.289 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springframework/util/ConcurrentReferenceHashMap$Reference is using a package name 'org/springframework/' which is considered infrastructure and types within it are not made reloadable
2015-11-24 12:56:48.289 INFO 40741 --- [Loader@14dad5dc] org.springsource.loaded.TypeRegistry : WhyNotReloadable? The type org/springframework/util/ConcurrentReferenceHashMap$Entry is using a package name 'org/springframework/' which is considered infrastructure and types within it are not made reloadable
> Building 80% > :bootRun
ただ、この設定を入れているときはなぜか割と高確率で exit 1 で異常終了してしまう。
015-11-24 12:57:48.662 INFO 40758 --- [ DestroyJavaVM] o.s.l.agent.SpringLoadedPreProcessor : SpringLoaded preprocessing: classname=java/util/IdentityHashMap$KeyIterator classloader=null typeRegistry=null
:bootRun FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':bootRun'.
> Process 'command '/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 10.923 secs
ちなみに ./graldew bootRun --stacktrace
で起動するとこんなログが出ていたが、これだけでは原因がよくわからなかった。
* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':bootRun'.
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:69)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:64)
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:203)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:185)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:66)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:50)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:25)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:110)
at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
at org.gradle.execution.DefaultBuildExecuter.access$000(DefaultBuildExecuter.java:23)
at org.gradle.execution.DefaultBuildExecuter$1.proceed(DefaultBuildExecuter.java:43)
at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
at org.gradle.initialization.DefaultGradleLauncher$4.run(DefaultGradleLauncher.java:154)
at org.gradle.internal.Factories$1.create(Factories.java:22)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:90)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:52)
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:151)
at org.gradle.initialization.DefaultGradleLauncher.access$200(DefaultGradleLauncher.java:32)
at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:99)
at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:93)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:90)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:62)
at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:93)
at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:82)
at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:94)
at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:28)
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:43)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:28)
at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:77)
at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:47)
at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:52)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
at org.gradle.util.Swapper.swap(Swapper.java:38)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.health.DaemonHealthTracker.execute(DaemonHealthTracker.java:47)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:66)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.health.HintGCAfterBuild.execute(HintGCAfterBuild.java:41)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:246)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
Caused by: org.gradle.process.internal.ExecException: Process 'command '/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1
at org.gradle.process.internal.DefaultExecHandle$ExecResultImpl.assertNormalExitValue(DefaultExecHandle.java:367)
at org.gradle.process.internal.DefaultJavaExecAction.execute(DefaultJavaExecAction.java:31)
at org.gradle.api.tasks.JavaExec.exec(JavaExec.java:75)
at org.springframework.boot.gradle.run.BootRunTask.exec(BootRunTask.java:63)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:75)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:227)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:220)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:209)
at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:585)
at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:568)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
... 68 more
既知の事象として issue が挙がっているのかもしれないが、ともあれ Spring Loaded は使えるようになった。
devtools の automatic restart
先ほど Tomcat 再起動をさせていたのは spring-boot-devtools の所作だった。これまで最初にドキュメントからコピペした build.gradle で何となく有効になっていたが、どういったものは把握していなかった。さらに進んだ「20. Developer tools」に説明がある。
「20.2 Automatic restart」にあるようにクラスパス上のファイルに変更があると devtools は Tomcat を再起動するようだ。デフォルトではクラスパス上のすべてのリソースの変更を検知して再起動をかける。この変更検知対象は設定で変更できるようだ。
devtools の再起動の仕組みは単に再起動しているわけではなかった。base と restart という二つのクラスローダを使い分けていて jar ファイルの中にいるような変更されないクラスについては base の方でロードし、src/main/java 配下のように頻繁に変更されるクラスは restart の方でロードしている。再起動するときはこの restart というクラスローダだけを作りなおすことで、単純に再起動するよりもかなりスピーディに起動できているとのこと。
そして restart よりもやはり reload が良いという場合は、Spring Loaded だけでなく ZeroTurnaround 社の JRebel も検討すると良いとのこと(これも実は使ったことがないので、機を見て試してみたい)。
とりあえずこの辺で
ということで、だいぶ長くなったので、この記事はこの辺で終わろうかと思います。
Spring Boot はとにかく手軽に試せるところが良いと思いました。Spring をこれまで使った経験があればアノテーションが何をしてくれるか想像がつくし、頑張って初期セットアップする必要がないのはスムーズで良いですね。
目下、テスト関連や Swagger 連携、OAuth2 あたりに関心があるので、まずはその辺を試してみたいと思っています。あとは、一応 Scala で使ったらどうかというのも一回自分でやってみるかなと。ただ、Gradle も Groovy で書いているわけなので Groovy でやってみるのもアリなのかなと思ったりしました。