Reputation: 2336
I have a Spring Boot application. I've added a lot of dependencies (unfortunately, looks I need all of them) and the startup time went up quite a lot. Just doing a SpringApplication.run(source, args)
takes 10 seconds.
While that might not be much compared to what are "used" to, I'm unhappy that it takes that much, mostly because it breaks the development flow. The application itself is rather small at this point, so I assume most of the time is related to the added dependencies, not the app classes themselves.
I assume the issue is classpath scanning, but I am not sure how to:
I assume that enhancing Spring to have parallel bean initialization during startup would speed up things, but that enhancement request has been open since 2011, without any progress. I see some other efforts in Spring Boot itself, such as Investigate Tomcat JarScanning speed improvements, but that is Tomcat specific and has been abandoned.
This article:
although aimed at integration tests, suggests using lazy-init=true
, however I do not know how to apply this to all beans in Spring Boot using Java configuration - any pointers here?
Any (other) suggestions would be welcome.
Upvotes: 184
Views: 173138
Reputation: 485
Using native image speeds up more than 20 times the batch start up.
Check this article: https://foojay.io/today/speed-up-your-spring-batch-with-native-image-and-graalvm/
For Spring Batch applications, Native Images are a game-changer.
By using GraalVM Native Image, you can build batch jobs that are fast, efficient, and perfectly suited for cloud environments where "scale to zero" is essential.
If you're dealing with micro-batch jobs that run for seconds, Native Image is a must-have. If your batch jobs are long-lived (running for hours), the benefit is less significant, but for fast, one-shot batch jobs, Native Image is unbeatable.
Upvotes: 0
Reputation: 16799
Checkout the Spring Boot Startup Report
https://github.com/maciejwalkowiak/spring-boot-startup-report
Spring Boot Startup Report library generates an interactive Spring Boot application startup report that lets you understand what contributes to the application startup time and perhaps helps to optimize it. startup report available in runtime as an interactive HTML page generating startup reports in integration tests flame chart search by class or an annotation
Features
Very cool utility IMHO.
Upvotes: 3
Reputation: 24637
The other answers don't go into the depth I like to see and provide no scientific evidence. The Spring Boot team went through an exercise for reducing startup time for Boot 2.0, and ticket 11226 contains a lot of useful information. There is also a ticket 7939 open to adding timing information to condition evaluation, but it doesn't seem to have a specific ETA.
The most useful, and methodical approach for debugging Boot startup has been done by Dave Syer. https://github.com/dsyer/spring-boot-startup-bench
I had a similar use case as well, so I took Dave's approach of micro-benchmarking with JMH and ran with it. The result is the boot-benchmark project. I designed it such that it can be used to measure startup time for any Spring Boot application, using the executable jar produced by bootJar
(previously called bootRepackage
in Boot 1.5) Gradle task. Feel free to use it and provide feedback.
My findings are as follows:
-XX:TieredStopAtLevel=1
would probably slow down your first request.Upvotes: 95
Reputation: 37993
WARNING: If you don't use Hibernate DDL for automatic DB schema generation and you don't use L2 cache, this answer is NOT applicable to you. Scroll ahead.
My finding is that Hibernate adds significant time to application startup. Disabling L2 cache and database initialization results in faster Spring Boot app startup. Leave cache ON for production and disable it for your development environment.
application.yml:
spring:
jpa:
generate-ddl: false
hibernate:
ddl-auto: none
properties:
hibernate:
cache:
use_second_level_cache: false
use_query_cache: false
Test results:
L2 cache is ON and ddl-auto: update
: 54 seconds
INFO 5024 --- [restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 23331 ms
INFO 5024 --- [restartedMain] b.n.spring.Application : Started Application in 54.251 seconds (JVM running for 63.766)
L2 cache is OFF and ddl-auto: none
: 32 seconds
INFO 10288 --- [restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 9863 ms
INFO 10288 --- [restartedMain] b.n.spring.Application : Started Application in 32.058 seconds (JVM running for 37.625)
Gained 22 seconds! Now I wonder what will I do with all this free time
Upvotes: 2
Reputation: 37993
I find it strange nobody suggested these optimizations before. Here're some general tips on optimizing project build and startup when developing:
WARNINGS
Upvotes: -3
Reputation: 11115
Spring Boot 2.2.M1 has added feature to support Lazy Initialization in Spring Boot.
By default, when an application context is being refreshed, every bean in the context is created and its dependencies are injected. By contrast, when a bean definition is configured to be initialized lazily it will not be created and its dependencies will not be injected until it’s needed.
Enabling Lazy Initialization Set spring.main.lazy-initialization
to true
When to Enable Lazy Initialization
lazy initialization can offer significant improvements in start up time but there are some notable downsides too and it’s important to enable it with care
For more details please check Doc
Update:
Spring Boot Spring Boot 2.4.0 - Startup Endpoint
Spring Boot 2.4.0 has added a new Startup endpoint that can be used to identify beans that are taking longer than expected to start. You can get more details about the Application Startup tracking here
Upvotes: 33
Reputation: 19
In my case, there was too much breakpoints. When I clicked "Mute Breakpoints" and restarted application in debug mode, application started in 10 times faster.
Upvotes: -5
Reputation: 7713
Well there is entire list of possible actions described here: https://spring.io/blog/2018/12/12/how-fast-is-spring
I will put the most important notes from Spring side (adjusted a little bit):
spring.config.location
(command line argument or System property etc.). Example for testing in IDE: spring.config.location=file://./src/main/resources/application.properties
.spring.jmx.enabled=false
(this is the default in Spring Boot 2.2)spring.main.lazy-initialization=true
in Spring Boot 2.2 (use LazyInitBeanFactoryPostProcessor
for older Spring).-noverify
. Also consider -XX:TieredStopAtLevel=1
(that will slow down the JIT later at the expense of the saved startup time).The mentioned LazyInitBeanFactoryPostProcessor
(you can use it for Spring 1.5 if you cannot apply flag spring.main.lazy-initialization=true
available from Spring 2.2):
public class LazyInitBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
definition.setLazyInit(true);
}
}
}
You can also use (or write your own - it's simple) something to analyse beans initialization time: https://github.com/lwaddicor/spring-startup-analysis
Hope it helps!
Upvotes: 9
Reputation: 54999
If you're trying to optimize development turn-around for manual testing, I strongly recommend the use of devtools.
Applications that use spring-boot-devtools will automatically restart whenever files on the classpath change.
Just recompile -- and the server will restart itself (for Groovy you only need to update the source file). if you're using an IDE (e.g. 'vscode'), it may automatically compile your java files, so just saving a java file can initiate a server restart, indirectly -- and Java becomes just as seamless as Groovy in this regard.
The beauty of this approach is that the incremental restart short-circuits some of the from-scratch startup steps -- so your service will be back up and running much more quickly!
Unfortunately, this doesn't help with startup times for deployment or automated unit testing.
Upvotes: 1
Reputation: 7868
As described in this question/answer, I think the best approach is to instead of adding only those you think you need, exclude the dependencies you know you don't need.
See: Minimise Spring Boot Startup Time
In summary:
You can see what is going on under the covers and enable debug logging as simple as specifying --debug when starting the application from the command-line. You can also specify debug=true in your application.properties.
Also, you can set the logging level in application.properties as simple as:
logging.level.org.springframework.web: DEBUG logging.level.org.hibernate: ERROR
If you detect an auto-configured module you don't want, it can be disabled. The docs for this can be found here: http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#using-boot-disabling-specific-auto-configuration
An example would look like:
@Configuration
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
}
Upvotes: 13
Reputation: 24591
Spring Boot does a lot of auto-configuration that may not be needed. So you may want to narrow down only auto-configuration that is needed for your app. To see full list of auto-configuration included, just run logging of org.springframework.boot.autoconfigure
in DEBUG mode (logging.level.org.springframework.boot.autoconfigure=DEBUG
in application.properties
). Another option is to run spring boot application with --debug
option: java -jar myproject-0.0.1-SNAPSHOT.jar --debug
There would be something like this in output:
=========================
AUTO-CONFIGURATION REPORT
=========================
Inspect this list and include only autoconfigurations you need:
@Configuration
@Import({
DispatcherServletAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
ErrorMvcAutoConfiguration.class,
HttpEncodingAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
JacksonAutoConfiguration.class,
ServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
ThymeleafAutoConfiguration.class,
WebMvcAutoConfiguration.class,
WebSocketAutoConfiguration.class,
})
public class SampleWebUiApplication {
Code was copied from this blog post.
Upvotes: 82
Reputation:
To me it sounds like you're using a wrong configuration setting. Start by checking myContainer and possible conflicts. To determine who is using the most resources you have to check the memory maps (see the amount of data!) for each dependency at a time - and that takes plenty of time, as well... (and SUDO privileges). By the way: are you usually testing the code against the dependencies?
Upvotes: -10