1. Introduction
Spring Boot gives us the ability to quickly setup and run services.
To enhance the development experience further, Spring released the spring-boot-devtools tool – as part of Spring Boot-1.3. This article will try to cover the benefits we can achieve using the new functionality.
We’ll cover the following topics:
- Property defaults
- Automatic Restart
- Live Reload
- Global settings
- Remote applications
1.1. Add Spring-Boot-Devtools in a Project
Adding spring-boot-devtools in a project is as simple as adding any other spring-boot module. In an existing spring-boot project, add the following dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
Do a clean build of the project, and you are now integrated with spring-boot-devtools. The newest version can be found here.
2. Property Defaults
Spring-boot does a lot of auto-configurations, including enabling caching by default to improve performance. One such example is caching of templates used by template engines, e.g. thymeleaf. But during development, it’s more important to see the changes as quickly as possible.
The default behavior of caching can be disabled for thymeleaf using the property spring.thymeleaf.cache=false in the application.properties file. We do not need to do this manually, introducing this spring-boot-devtools does this automatically for us.
3. Automatic Restart
In a typical application development environment, a developer would make some changes, build the project and deploy/start the application for new changes to take effect, or else try to leverage JRebel, etc.
Using spring-boot-devtools, this process is also automated. Whenever files change in the classpath, applications using spring-boot-devtools will cause the application to restart. The benefit of this feature is the time required to verify the changes made is considerably reduced:
19:45:44.804 ... - Included patterns for restart : []
19:45:44.809 ... - Excluded patterns for restart : [/spring-boot-starter/target/classes/, /spring-boot-autoconfigure/target/classes/, /spring-boot-starter-[\w-]+/, /spring-boot/target/classes/, /spring-boot-actuator/target/classes/, /spring-boot-devtools/target/classes/]
19:45:44.810 ... - Matching URLs for reloading : [file:/.../target/test-classes/, file:/.../target/classes/]
:: Spring Boot :: (v1.5.2.RELEASE)
2017-03-12 19:45:45.174 ...: Starting Application on machine with PID 7724 (<some path>\target\classes started by user in <project name>)
2017-03-12 19:45:45.175 ...: No active profile set, falling back to default profiles: default
2017-03-12 19:45:45.510 ...: Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@385c3ca3: startup date [Sun Mar 12 19:45:45 IST 2017]; root of context hierarchy
As seen in the logs, the thread that has spawned the application is not a main rather a restartedMain thread. Any changes made in the project be it a java file change will cause an automated restart of the project:
2017-03-12 19:53:46.204 ...: Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@385c3ca3: startup date [Sun Mar 12 19:45:45 IST 2017]; root of context hierarchy
2017-03-12 19:53:46.208 ...: Unregistering JMX-exposed beans on shutdown
:: Spring Boot :: (v1.5.2.RELEASE)
2017-03-12 19:53:46.587 ...: Starting Application on machine with PID 7724 (<project path>\target\classes started by user in <project name>)
2017-03-12 19:53:46.588 ...: No active profile set, falling back to default profiles: default
2017-03-12 19:53:46.591 ...: Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@acaf4a1: startup date [Sun Mar 12 19:53:46 IST 2017]; root of context hierarchy
4. Live Reload
spring-boot-devtools module includes an embedded LiveReload server that is used to trigger a browser refresh when a resource is changed.
For this to happen in the browser we need to install the LiveReload plugin one such implementation is Remote Live Reload for Chrome.
5. Global Settings
spring-boot-devtools provides a way to configure global settings that are not coupled with any application. This file is named as .spring-boot-devtools.properties and it located at $HOME.
6. Remote Applications
6.1. Remote Debugging via HTTP (Remote Debug Tunnel)
spring-boot-devtools provides out of the box remote debugging capabilities via HTTP, to have this feature it is required that spring-boot-devtools are packaged as part of the application. This can be achieved by disabling excludeDevtools configuration in the plugin in maven.
Here’s a quick sample:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeDevtools>false</excludeDevtools>
</configuration>
</plugin>
</plugins>
</build>
Now for remote debugging via HTTP to work, following steps have to be taken:
- An application being deployed and started on the server, should be started with Remote Debugging enabled:
As we can see, the remote debugging port is not mentioned here. Hence, java will choose a random port-Xdebug -Xrunjdwp:server=y,transport=dt_socket,suspend=n
- For the same project, open the Launch configurations, choose the following options:
Select main class: org.springframework.boot.devtools.RemoteSpringApplication
In program arguments, add the URL for the application, e.g. http://localhost:8080 - Default port for debugger via spring-boot application is 8000 and can be overridden via:
spring.devtools.remote.debug.local-port=8010
- Now create a remote-debug configuration, setting up the port as 8010 as configured via properties or 8000, if sticking to defaults
Here’s what the log will look like:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ ___ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | | _ \___ _ __ ___| |_ ___ \ \ \ \
\\/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' \/ _ \ _/ -_) ) ) ) )
' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / /
=========|_|==============|___/===================================/_/_/_/
:: Spring Boot Remote :: (v1.5.2.RELEASE)
2017-03-12 22:24:11.089 ...: Starting RemoteSpringApplication v1.5.2.RELEASE on machine with PID 10476 (..\org\springframework\boot\spring-boot-devtools\1.5.2.RELEASE\spring-boot-devtools-1.5.2.RELEASE.jar started by user in project)
2017-03-12 22:24:11.097 ...: No active profile set, falling back to default profiles: default
2017-03-12 22:24:11.357 ...: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@11e21d0e: startup date [Sun Mar 12 22:24:11 IST 2017]; root of context hierarchy
2017-03-12 22:24:11.869 ...: The connection to http://localhost:8080 is insecure. You should use a URL starting with 'https://'.
2017-03-12 22:24:11.949 ...: LiveReload server is running on port 35729
2017-03-12 22:24:11.983 ...: Started RemoteSpringApplication in 1.24 seconds (JVM running for 1.802)
2017-03-12 22:24:34.324 ...: Remote debug connection opened
6.2. Remote Update
The remote client monitors the application classpath for changes as is done for remote restart feature. Any change in the classpath causes, the updated resource to be pushed to the remote application and a restart is triggered.
Changes are pushed when the remote client is up and running, as monitoring for changed files is only possible then.
Here’s what that looks like in the logs:
2017-03-12 22:33:11.613 INFO 1484 ...: Remote debug connection opened
2017-03-12 22:33:21.869 INFO 1484 ...: Uploaded 1 class resource
7. Conclusion
With this quick article, we have just demonstrated how we can leverage the spring-boot-devtools module to make the developer experience better and reduce the development time by automating a lot of activities.