From the translator: since the Spring Framework is one of the main frameworks on which we build CUBA , news about the new features of Spring does not pass unnoticed by us. Lazy initialization is one of the ways to reduce the time of the first application load, which in our age of universal use of microservices is an important metric. For those who prefer reading video to reading, there is a 10-minute speech by Josh Long on the topic of the article.
The recently announced first milestone release of Spring Boot 2.2 adds support for lazy initialization. In this article, we will look at new functionality and explain how to enable it.
The Spring Framework supports lazy initialization since its source code moved to git eleven years ago. By default, when the application context is updated, each bin is recreated and its dependencies are injected. In contrast, if a bean is configured for lazy initialization, it will not be created and its dependencies will not be put down until it is necessary.
In any version of Spring Boot, you can enable lazy initialization if you don't mind BeanFactoryPostProcessor
with your hands with BeanFactoryPostProcessor
. Spring Boot 2.2 simply simplifies this process by introducing a new property, spring.main.lazy-initialization
(there are also equivalent methods in SpringApplication
and SpringApplicationBuilder
). When this property is set to true
, the application beans will be configured to use lazy initialization.
Lazy initialization can significantly reduce the start time of your application, since at this stage less classes are loaded and fewer bins are created. For example, a small web application that uses Actuator and Spring Security usually starts 2.5 seconds. And with lazy initialization, this process takes 2 seconds. The exact values ​​of the acceleration will vary from application to application, depending on the structure of the dependency graph of bins.
Translator's note: I started this example by writing Spring Boot 2.2 dependencies, and the launch time with lazy initialization was 3 seconds, and without it - 4. I think that for more serious applications, a significant gain in start time due to the use of lazy initialization we will not see. Upd: on the advice of alek_sys, disabled validation and update of the database schema and enabled lazy initialization of JPA for both cases - it turned out 2.7 and 3.7 seconds before the appearance of the Started WebApplication in...
Spring Boot DevTools provide a marked acceleration of development. Instead of restarting the JVM and the application, every time you change something, DevTools “hot restart” the application in the same JVM. A significant advantage of this restart is that it gives JIT the opportunity to optimize the code that is executed when the application starts. After several restarts, the original time of 2.5 seconds is reduced by almost 80% to 500 ms. With lazy initialization, everything is even better. Setting the spring.main.lazy-initialization
property shows the restart time directly in the IDE to 400 ms.
As was shown above, turning on lazy initialization can quite seriously reduce the application launch time. And, perhaps, you will have an overwhelming desire to use it all the time, or, at a minimum, you will be wondering why lazy initialization is not enabled by default. There are several possible negative effects that are best clarified immediately.
The fact that classes are not loaded, and the bins are not created until they are needed, can mask problems that could have been detected earlier in the application launch phase. For example, it may be the absence of the required class, a memory overflow or an error due to incorrect configuration.
In web applications, lazy configuration can increase the latency of HTTP requests that cause initialization of the beans. This is usually the first request, but there may be additional unwanted effects affecting load balancing or automatic scaling.
If you are not sure how exactly lazy initialization affects your application or you want to check that other aspects of the framework are right for you and do what you need, then it will be useful for you to use the debugger for this. By setting the breakpoint on the bean's constructor, you can see at what exact moment the bean is initialized. For example, in a web application written in Spring Boot and with lazy initialization enabled, you can see that the bins marked with the @Controller
annotation @Controller
not created before the first request to DispatcerServlet
Spring MVC or to DispatchHandler
Spring WebFlux.
As we have already seen above, lazy initialization offers noticeable improvements during the launch of the application, but there are also down sides, so you need to use this feature very carefully.
One area where lazy initialization can bring dividends (with almost no overhead) is the application development process. While you are writing an application, reduced restart time, which is provided by lazy initialization in combination with DevTools, can save you considerable time.
Where else can you get the benefits of using lazy initialization - so it is in integration tests. You may already be using "slicing" tests to reduce execution time, limiting the number of initialized bins in some types of tests. Lazy initialization provides an alternative opportunity to achieve the same result. If you are not in the right position to change the structure of the application for “slice” tests, or for specifically your tests there is no suitable “slicing”, then enabling lazy initialization will limit the number of bins to those that are used only in your test. This will reduce the test execution time, especially if they are run in an isolated environment during development.
Include a lazy initialization on the prode last. And, if you decide to do this, do it with caution. For web applications, the container manager can rely on the entry /health
point, which usually responds fairly quickly, but you have to remember that, potentially, the first calls can take longer than usual. You should also remember about the amount of memory allocated for the JVM, so as not to encounter overflow when all components are initialized.
Source: https://habr.com/ru/post/445592/
All Articles