Yesterday, Spring Boot 1.3.0.M2 has been released!
In this article, I'd like to introduce how to start 1.3 and super cool new feature called DevTools (Blog, Doc).
How to start
Most easy way to create a Spring Boot project must be using SPRING INITIALIZER. Check modules you need and click "Generate Project", then a blank project will be downloaded.
For example, this link produces a simple Spring Boot 1.3.0.M2 project including the following modules:
- web
- thymeleaf
- devtools
Some IDEs support generating projects by SPRING INITIALIZER.
SPRING INITIALIZER with Spring Tool Suite
Choose "File" -> "New" -> "Other" -> "Spring" -> "Spring Starter Project".
Select "1.3.0.M2" as "Boot Version" and check some modules from "Style" panel. In this demo, "web" and "thymeleaf" are chosen.
Finally, click "Finish", then demo project will be imported!
Right click DemoApplication
and run as "Spring Boot Application".
Demo Application will be started!
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.3.0.M2)
2015-07-11 11:43:20.564 INFO 2403 --- [ main] demo.DemoApplication : Starting DemoApplication on making.local with PID 2403 (/Users/maki/sts/demo/target/classes started by maki in /Users/maki/sts/demo)
...(omitted)...
2015-07-11 11:43:24.011 INFO 2403 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2015-07-11 11:43:24.019 INFO 2403 --- [ main] demo.DemoApplication : Started DemoApplication in 3.71 seconds (JVM running for 4.263)
SPRING INITIALIZER with IntelliJ IDEA
Choose "File" -> "New" -> "Project" -> "Spring Initializer".
Input project information (Defaults are enough, so far).
Select "1.3.0.M2" as "Boot Version" and check some modules from "Dependencies" panel. In this demo, "web" and "thymeleaf" are chosen.
After that, it's a normal procedure as same as you usually do.
Try "Devtools Support"
I think most significant feature of 1.3 is "DevTools Support".
To use devtools, simply add the dependency in your pom.xml as follows:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
Of course, you can choose spring-boot-devtools
in Spring Initializer.
This nice module enables the following features to help us in dev-phase:
- Disabling template cache
- Auto restart Class Loader
- Live reload browser
- Remote debug & restart
Disabling template cache
Before 1.3, template engines cache template. From the viewpoint of performance, it's good. However, in developoment, it's unconvenient because it requires restarting the application to reflect the change of a template.
To avoid cache, we had to set spring.thymeleaf.cache=false
in application.properties
and enabled cache at runtime like java -jar app.jar --spring.thymeleaf.cache=true
.
By adding org.springframework.boot:spring-boot-devtools
, the properties bellow are automatically configured:
spring.thymeleaf.cache=false
spring.freemarker.cache=false
spring.groovy.template.cache=false
spring.velocity.cache=false
spring.mustache.cache=false
Wonderfully, features from devtools are automatically disabled via java -jar app.jar
.
So, we no longer need to toggle spring.thymeleaf.cache
!!
Auto restart Class Loader
Look the next tiny application:
package demo;
import javax.annotation.PostConstruct;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
@PostConstruct
void demo() {
System.out.println("****hello!****");
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Run this app:
2015-07-11 16:04:37.750 INFO 2570 --- [ restartedMain] demo.DemoApplication : Starting DemoApplication on making.local with PID 2570 (/Users/maki/sts/demo/target/classes started by maki in /Users/maki/sts/demo)
2015-07-11 16:04:37.795 INFO 2570 --- [ restartedMain] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@222f3c6a: startup date [Sat Jul 11 16:04:37 JST 2015]; root of context hierarchy
... (omitted) ...
2015-07-11 16:04:39.838 INFO 2570 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2046 ms
2015-07-11 16:04:40.642 INFO 2570 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2015-07-11 16:04:40.648 INFO 2570 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2015-07-11 16:04:40.649 INFO 2570 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2015-07-11 16:04:40.649 INFO 2570 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'resourceUrlEncodingFilter' to: [/*]
****hello!****
2015-07-11 16:04:41.003 INFO 2570 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice:
... (omitted) ...
2015-07-11 16:04:41.612 INFO 2570 --- [ restartedMain] demo.DemoApplication
As you can see, thread name has been changed from main
to restartedMain
.
Once the app start, it will be restarted according to the change of class file.
Let's change to System.out.println("****Spring Boot!****");
in demo
method.
Save & Compile the source code, then you can see the console log is output and find the change are reflected.
2015-07-11 16:08:31.264 INFO 2570 --- [ Thread-4] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@222f3c6a: startup date [Sat Jul 11 16:04:37 JST 2015]; root of context hierarchy
2015-07-11 16:08:31.269 INFO 2570 --- [ Thread-4] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.3.0.M2)
2015-07-11 16:08:31.524 INFO 2570 --- [ restartedMain] demo.DemoApplication : Starting DemoApplication on making.local with PID 2570 (/Users/maki/sts/demo/target/classes started by maki in /Users/maki/sts/demo)
2015-07-11 16:08:31.528 INFO 2570 --- [ restartedMain] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6d20eb7f: startup date [Sat Jul 11 16:08:31 JST 2015]; root of context hierarchy
... (omitted) ...
2015-07-11 16:08:32.008 INFO 2570 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 480 ms
2015-07-11 16:08:32.165 INFO 2570 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2015-07-11 16:08:32.166 INFO 2570 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2015-07-11 16:08:32.166 INFO 2570 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2015-07-11 16:08:32.166 INFO 2570 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'resourceUrlEncodingFilter' to: [/*]
****Spring Boot!****
2015-07-11 16:08:32.220 INFO 2570 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice:
... (omitted) ...
2015-07-11 16:08:32.356 INFO 2570 --- [ restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2015-07-11 16:08:32.359 INFO 2570 --- [ restartedMain] demo.DemoApplication : Started DemoApplication in 0.867 seconds (JVM running for 235.486)
Time to restart looks much faster than the initial spin up time (In this demo, it took only 0.867 sec). The reason why is described in the manual.
Demo
Live reload browser
Amazingly, devtools embeds a LiveReload server which trigger a browser refresh when the resources are changed.
To use this functionality, LiveReload browser extension is required. You can install from http://livereload.com/extensions/ .
To show the demonstration, I use the following small web application:
DemoApplication.java
package demo;
import java.time.LocalDateTime;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@SpringBootApplication
@Controller
public class DemoApplication {
@RequestMapping("/")
String index(Model model) {
model.addAttribute("hello", "Hello! @" + LocalDateTime.now());
return "index";
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title></title>
<link rel="stylesheet" th:href="@{/style.css}"></link>
</head>
<body>
<p>
<span th:text="${hello}">Hello!</span>
</p>
</body>
</html>
style.css
body {
font-size: 12px;
}
Take a look at the demo :)
Note that I did not refresh the browser by myself at all.
The combination of AutoRestart & LiveReload is awesome!
Remote debug & restart
Devtools enable us to access deployed remote application.
You can debug and auto-restart the remote app via org.springframework.boot.devtools.RemoteSpringApplication
.
To know the details, refer the manual :)
In Spring Boot 1.3, not only devtools, other interesting features are alse added.
Try Spring Boot 1.3 & DevTools and have a fun ;)