Accelerated Development with Spring Boot DevTools

How to speed up development on Spring Boot with DevTools and make this process more enjoyable and productive?

Customization


As usual when developing on Spring Boot, the setup is quite simple. All you have to do is add the correct dependency and you're done. Spring Boot finds it and automatically configures DevTools accordingly.

If you are using Maven:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> 

If using Gradle:

 configurations { developmentOnly runtimeClasspath { extendsFrom developmentOnly } } dependencies { developmentOnly("org.springframework.boot:spring-boot-devtools") } 

Please note that the dependency is declared as optional. This is important because such a dependency declaration prevents the DevTools dependency from being transitively applied to other modules depending on your project.

Auto restart


Whenever file changes occur in your classpath, DevTools will automatically restart your working application with the new changes. For local development, this can be useful since you do not need to redeploy the application manually.

This alone would not be so useful, since restarting can still take too much time. Fortunately, such a restart is much faster than a regular restart due to the tricky trick that DevTools uses.

The fact is that when developing an application, you usually change a class or several and want to check the results in your running application for feedback. You make minor changes to your application, while most of the loaded classes come from frameworks and third-party libraries.

Under the hood of Spring DevTools, two class loaders are used - base and restart . Classes that do not change are loaded by the base loader base . The classes you work with are loaded using the restart loader. Each time you restart, the boot loader is recreated. Thus, restarting the application is much faster than usual, and can be a real alternative to reloading a dynamic class using tools such as JRebel.

Initialization of restart in IDE


A restart is triggered every time a file changes in your classpath. However, this process depends on your IDE. This means that just changing your java files is not enough. The important thing is when your IDE actually updates .class files in your classpath.

When using IntelliJ IDEA, you need to run the build command in your project ( Ctrl + F9 or Build β†’ Build Project ). You can also configure the build command to run automatically in IDEA . In addition, you can open the Spring Boot startup configuration and determine what happens when the application update starts ( Ctrl + F10 ):



In the first combo box, you can select Update trigger file to start the DevTools restart each time the Update action is performed. Alternatively, you can even select the Hot Swap option and try to restart the application using DevTools only if the Hot Swap execution failed.

In the second combo box, you can configure the reboot of all static resources and templates when the IDEA window loses focus (for example, when switching to the browser window).

In Eclipse, it's easy enough to save your files.

Development Only


Spring Boot DevTools are intended only for development, and not for production operation of the application. If your application detects that you are working in a production environment, DevTools is automatically disabled.

For this purpose, whenever you launch your application as a fully packaged artifact, such as a jar with an integrated application server, it is considered a production application:

 java -jar devtools-example-1.0.0.jar 

The same applies when your application is launched through a special class loader, for example, on an application server.

On the contrary, when you run unpacked artifacts (for example, in your IDE), your application is considered in development mode. The same applies to using spring-boot-plugin to run the application:

Maven:

 mvn spring-boot:run 

Gradle:

 gradle bootRun 

LiveReload


LiveReload is a useful tool that allows you to instantly refresh a page in a browser whenever you make changes to files such as HTML, CSS, images, and more. It even preprocesses files as needed - this means automatic compilation of SASS or LESS files.



Spring DevTools automatically starts a local instance of the LiveReload server that tracks your files. All you have to do is install the extension for the browser , and you're done. It is not only useful for developing the external interface of your application (in case you distribute it as part of the Spring application artifact), but can also be used to monitor and reload the output of your REST API.

Property Override


When developing an application locally, you usually have different configuration needs than when working in a production environment. One example would be caching. In a production environment, dependency on various caches (such as engine template caches, caching headers for static resources, etc.) is extremely important. During development, it may use old data and not reflect your latest changes. Another example would be advanced logging, which may be useful in development but too detailed for the production environment.

It is too difficult to manage two types of configuration yourself. The good news is that Spring Boot DevTools, by default, sets up many properties for your local development.

 spring.thymeleaf.cache=false spring.freemarker.cache=false spring.groovy.template.cache=false spring.mustache.cache=false server.servlet.session.persistent=true spring.h2.console.enabled=true spring.resources.cache.period=0 spring.resources.chain.cache=false spring.template.provider.cache=false spring.mvc.log-resolved-exception=true server.servlet.jsp.init-parameters.development=true spring.reactor.stacktrace-mode.enabled=true 

You can find a list of all the properties in the DevToolsPropertyDefaultsPostProcessor class.

Remote connection


In addition to local development, you can also connect to a remote application running DevTools. This tool is not intended for production environments as it can pose a serious safety risk. However, it can be very useful in a pre-production environment.

Enabling Remote Connection


Remote connection is not enabled by default. You need to explicitly enable it by modifying the pom file:

 <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludeDevtools>false</excludeDevtools> </configuration> </plugin> </plugins> </build> 

Or with gradle, you need to set excludeDevtools = false :

 bootWar { excludeDevtools = false } 

Then you need to set a password that will be used for authentication when connecting to the remote application:

 spring.devtools.remote.secret=somesecret 

Connect to a remote application


After starting the remote application, you can start the remote connection session. Now all you have to do is run org.springframework.boot.devtools.RemoteSpringApplication with the URL of your remote application as an argument. Please note that you should use https if possible.

Starting a remote connection is easy in your IDE. In IDEA, you just need to create a new launch configuration. Go to Run β†’ Edit Configurations ... and create a new configuration with the + icon in the upper left corner. Select an application type.

For the Main class, select RemoteSpringApplication from the DevTools module and pass the URL of your remote application as an argument to the program.



After starting this configuration, you should see a similar output if the connection to the remote application was successful.



After connecting to a remote application, DevTools monitors class path changes in the same way as for local development. However, instead of a local restart, it transfers the changes to the remote server and initiates a restart there. This can be much faster than creating an application and deploying it to a remote machine.

Global configuration


You can customize DevTools using configuration properties, as with any other Spring application. This usually means editing the application.properties of your project. This configuration is separate for each application.

However, in some scenarios it may be convenient to have a global configuration for ALL applications running on the same computer. You can create a properties file called .spring-boot-devtools.properties located in your $ HOME directory. The declaration stated in this file applies to all applications using DevTools.

Limitations


Live reload


A Spring application using DevTools automatically starts the LiveReload server. Unfortunately, only one instance of this server can be started at a time. More precisely, only the first instance will work. This applies not only to several instances of Spring applications with DevTools, but also to any other applications that also use LiverReload under the hood, such as Gatsby in development mode.

If you want to configure the Spring application so that it does not start the LiveReload server, then this can be done in your application.properties file:

 spring.devtools.livereload.enabled=false 

Shutdown hook


DevTools depend on the shutdown hook attribute of the SpringApplication class. The class will not work correctly if you manually disabled the attribute using:

 springApplication.setRegisterShutdownHook(false); 

The attribute is enabled by default, so you don’t have to worry about it unless you explicitly disable it.

Collisions with third-party libraries


Although DevTools should usually work correctly, they may have conflicts with third-party libraries. In particular, there is a known problem with deserialization using the standard ObjectInputStream .

In the event of such a conflict, you can disable the automatic restart by setting:

 spring.devtools.restart.enabled=false 

Restarting will no longer work. However, the restart classloader will still be used. If you need to completely disable the class loader, you must do this before starting the application:

 public static void main(String[] args) { System.setProperty("spring.devtools.restart.enabled", "false"); SpringApplication.run(MyApp.class, args); } 

Even if you do not use automatic restart, you can still use other DevTools features.

Enabling Delayed Initialization


You can mark individual components as lazily initialized using annotations @Lazy. This feature has been available for quite some time. Starting with Spring Boot 2.2, you can switch delayed initialization for all your bean components using spring.main.lazy-initialization = true .

This can be used alone or in combination with DevTools for an even faster restart .

DevTools allows you to hot restart your application in the same JVM. A significant advantage of a hot restart is that it gives JIT more options for optimizing the code used to launch your application. After several restarts, the initial time of 2500 ms is reduced by almost 80% and approaches 500 ms. With lazy initialization, we can achieve better results. When installing spring.main.lazy-initialization, our application restarts after 400 ms directly in the IDE.

Using delayed initialization for all of your beans in a production application is doubtful. This procedure provides superior startup performance gains due to longer first-time requests to individual bean components. More importantly, your application does not stop working quickly. But instead of crashing immediately upon starting the application, it will fail only after directly requesting the incorrectly configured component. This can be very dangerous since you will not find many errors until it is too late. However, mass delayed initialization can be useful to speed up development time, because when working with a certain function, you usually work only on part of your application, and do not use the rest. The ideal compromise would be to enable mass delayed initialization only for local development (say, using a spring profile) and disable it for deployed higher environments.

Conclusion


DevTools speeds up and simplifies Spring Boot application development by providing automatic restart and LiveReload functionality. In addition to this, it sets various properties for values ​​that are more suitable for local development. In addition, it allows you to remotely connect to your application and at the same time use most of its functions. When starting the application in production, DevTools are not used. See the official documentation for details.

Source: https://habr.com/ru/post/479382/


All Articles