This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Boot 3.3.4! |
This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Boot 3.3.4! |
The SpringApplication
class provides a convenient way to bootstrap a Spring application that is started from a main()
method.
In many situations, you can delegate to the static SpringApplication.run
method, as shown in the following example:
-
Java
-
Kotlin
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
When your application starts, you should see something similar to the following output:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.4.0-SNAPSHOT)
2024-10-04T13:31:49.282Z INFO 83530 --- [ main] o.s.b.d.f.logexample.MyApplication : Starting MyApplication using Java 17.0.12 with PID 83530 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
2024-10-04T13:31:49.300Z INFO 83530 --- [ main] o.s.b.d.f.logexample.MyApplication : No active profile set, falling back to 1 default profile: "default"
2024-10-04T13:31:51.984Z INFO 83530 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2024-10-04T13:31:52.002Z INFO 83530 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2024-10-04T13:31:52.003Z INFO 83530 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.30]
2024-10-04T13:31:52.075Z INFO 83530 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2024-10-04T13:31:52.077Z INFO 83530 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2518 ms
2024-10-04T13:31:53.392Z INFO 83530 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
2024-10-04T13:31:53.427Z INFO 83530 --- [ main] o.s.b.d.f.logexample.MyApplication : Started MyApplication in 5.607 seconds (process running for 6.373)
2024-10-04T13:31:53.456Z INFO 83530 --- [ionShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete
2024-10-04T13:31:53.493Z INFO 83530 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete
By default, INFO
logging messages are shown, including some relevant startup details, such as the user that launched the application.
If you need a log level other than INFO
, you can set it, as described in Log Levels.
The application version is determined using the implementation version from the main application class’s package.
Startup information logging can be turned off by setting spring.main.log-startup-info
to false
.
This will also turn off logging of the application’s active profiles.
To add additional logging during startup, you can override logStartupInfo(boolean) in a subclass of SpringApplication .
|
To add additional logging during startup, you can override logStartupInfo(boolean) in a subclass of SpringApplication .
|
Startup Failure
If your application fails to start, registered FailureAnalyzers
get a chance to provide a dedicated error message and a concrete action to fix the problem.
For instance, if you start a web application on port 8080
and that port is already in use, you should see something similar to the following message:
***************************
APPLICATION FAILED TO START
***************************
Description:
Embedded servlet container failed to start. Port 8080 was already in use.
Action:
Identify and stop the process that is listening on port 8080 or configure this application to listen on another port.
Spring Boot provides numerous FailureAnalyzer implementations, and you can add your own.
|
If no failure analyzers are able to handle the exception, you can still display the full conditions report to better understand what went wrong.
To do so, you need to enable the debug
property or enable DEBUG
logging for org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
.
For instance, if you are running your application by using java -jar
, you can enable the debug
property as follows:
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
Spring Boot provides numerous FailureAnalyzer implementations, and you can add your own.
|
Lazy Initialization
SpringApplication
allows an application to be initialized lazily.
When lazy initialization is enabled, beans are created as they are needed rather than during application startup.
As a result, enabling lazy initialization can reduce the time that it takes your application to start.
In a web application, enabling lazy initialization will result in many web-related beans not being initialized until an HTTP request is received.
A downside of lazy initialization is that it can delay the discovery of a problem with the application. If a misconfigured bean is initialized lazily, a failure will no longer occur during startup and the problem will only become apparent when the bean is initialized. Care must also be taken to ensure that the JVM has sufficient memory to accommodate all of the application’s beans and not just those that are initialized during startup. For these reasons, lazy initialization is not enabled by default and it is recommended that fine-tuning of the JVM’s heap size is done before enabling lazy initialization.
Lazy initialization can be enabled programmatically using the lazyInitialization
method on SpringApplicationBuilder
or the setLazyInitialization
method on SpringApplication
.
Alternatively, it can be enabled using the spring.main.lazy-initialization
property as shown in the following example:
-
Properties
-
YAML
spring.main.lazy-initialization=true
spring:
main:
lazy-initialization: true
If you want to disable lazy initialization for certain beans while using lazy initialization for the rest of the application, you can explicitly set their lazy attribute to false using the @Lazy(false) annotation.
|
If you want to disable lazy initialization for certain beans while using lazy initialization for the rest of the application, you can explicitly set their lazy attribute to false using the @Lazy(false) annotation.
|
Customizing the Banner
The banner that is printed on start up can be changed by adding a banner.txt
file to your classpath or by setting the spring.banner.location
property to the location of such a file.
If the file has an encoding other than UTF-8, you can set spring.banner.charset
.
Inside your banner.txt
file, you can use any key available in the Environment
as well as any of the following placeholders:
Variable | Description |
---|---|
|
The version number of your application, as declared in |
|
The version number of your application, as declared in |
|
The Spring Boot version that you are using.
For example |
|
The Spring Boot version that you are using, formatted for display (surrounded with brackets and prefixed with |
|
Where |
|
The title of your application, as declared in |
The SpringApplication.setBanner(…) method can be used if you want to generate a banner programmatically.
Use the org.springframework.boot.Banner interface and implement your own printBanner() method.
|
You can also use the spring.main.banner-mode
property to determine if the banner has to be printed on System.out
(console
), sent to the configured logger (log
), or not produced at all (off
).
The printed banner is registered as a singleton bean under the following name: springBootBanner
.
The To use the |
Variable | Description |
---|---|
|
The version number of your application, as declared in |
|
The version number of your application, as declared in |
|
The Spring Boot version that you are using.
For example |
|
The Spring Boot version that you are using, formatted for display (surrounded with brackets and prefixed with |
|
Where |
|
The title of your application, as declared in |
The SpringApplication.setBanner(…) method can be used if you want to generate a banner programmatically.
Use the org.springframework.boot.Banner interface and implement your own printBanner() method.
|
The To use the |
Customizing SpringApplication
If the SpringApplication
defaults are not to your taste, you can instead create a local instance and customize it.
For example, to turn off the banner, you could write:
-
Java
-
Kotlin
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.run(args);
}
}
import org.springframework.boot.Banner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args) {
setBannerMode(Banner.Mode.OFF)
}
}
The constructor arguments passed to SpringApplication are configuration sources for Spring beans.
In most cases, these are references to @Configuration classes, but they could also be direct references @Component classes.
|
It is also possible to configure the SpringApplication
by using an application.properties
file.
See Externalized Configuration for details.
For a complete list of the configuration options, see the SpringApplication
API documentation.
The constructor arguments passed to SpringApplication are configuration sources for Spring beans.
In most cases, these are references to @Configuration classes, but they could also be direct references @Component classes.
|
Fluent Builder API
If you need to build an ApplicationContext
hierarchy (multiple contexts with a parent/child relationship) or if you prefer using a fluent builder API, you can use the SpringApplicationBuilder
.
The SpringApplicationBuilder
lets you chain together multiple method calls and includes parent
and child
methods that let you create a hierarchy, as shown in the following example:
-
Java
-
Kotlin
new SpringApplicationBuilder().sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
SpringApplicationBuilder()
.sources(Parent::class.java)
.child(Application::class.java)
.bannerMode(Banner.Mode.OFF)
.run(*args)
There are some restrictions when creating an ApplicationContext hierarchy.
For example, Web components must be contained within the child context, and the same Environment is used for both parent and child contexts.
See the SpringApplicationBuilder API documentation for full details.
|
There are some restrictions when creating an ApplicationContext hierarchy.
For example, Web components must be contained within the child context, and the same Environment is used for both parent and child contexts.
See the SpringApplicationBuilder API documentation for full details.
|
Application Availability
When deployed on platforms, applications can provide information about their availability to the platform using infrastructure such as Kubernetes Probes. Spring Boot includes out-of-the box support for the commonly used “liveness” and “readiness” availability states. If you are using Spring Boot’s “actuator” support then these states are exposed as health endpoint groups.
In addition, you can also obtain availability states by injecting the ApplicationAvailability
interface into your own beans.
Liveness State
The “Liveness” state of an application tells whether its internal state allows it to work correctly, or recover by itself if it is currently failing. A broken “Liveness” state means that the application is in a state that it cannot recover from, and the infrastructure should restart the application.
In general, the "Liveness" state should not be based on external checks, such as health checks. If it did, a failing external system (a database, a Web API, an external cache) would trigger massive restarts and cascading failures across the platform. |
The internal state of Spring Boot applications is mostly represented by the Spring ApplicationContext
.
If the application context has started successfully, Spring Boot assumes that the application is in a valid state.
An application is considered live as soon as the context has been refreshed, see Spring Boot application lifecycle and related Application Events.
Readiness State
The “Readiness” state of an application tells whether the application is ready to handle traffic.
A failing “Readiness” state tells the platform that it should not route traffic to the application for now.
This typically happens during startup, while CommandLineRunner
and ApplicationRunner
components are being processed, or at any time if the application decides that it is too busy for additional traffic.
An application is considered ready as soon as application and command-line runners have been called, see Spring Boot application lifecycle and related Application Events.
Tasks expected to run during startup should be executed by CommandLineRunner and ApplicationRunner components instead of using Spring component lifecycle callbacks such as @PostConstruct .
|
Managing the Application Availability State
Application components can retrieve the current availability state at any time, by injecting the ApplicationAvailability
interface and calling methods on it.
More often, applications will want to listen to state updates or update the state of the application.
For example, we can export the "Readiness" state of the application to a file so that a Kubernetes "exec Probe" can look at this file:
-
Java
-
Kotlin
import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.ReadinessState;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class MyReadinessStateExporter {
@EventListener
public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {
switch (event.getState()) {
case ACCEPTING_TRAFFIC -> {
// create file /tmp/healthy
}
case REFUSING_TRAFFIC -> {
// remove file /tmp/healthy
}
}
}
}
import org.springframework.boot.availability.AvailabilityChangeEvent
import org.springframework.boot.availability.ReadinessState
import org.springframework.context.event.EventListener
import org.springframework.stereotype.Component
@Component
class MyReadinessStateExporter {
@EventListener
fun onStateChange(event: AvailabilityChangeEvent<ReadinessState?>) {
when (event.state) {
ReadinessState.ACCEPTING_TRAFFIC -> {
// create file /tmp/healthy
}
ReadinessState.REFUSING_TRAFFIC -> {
// remove file /tmp/healthy
}
else -> {
// ...
}
}
}
}
We can also update the state of the application, when the application breaks and cannot recover:
-
Java
-
Kotlin
import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.LivenessState;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
@Component
public class MyLocalCacheVerifier {
private final ApplicationEventPublisher eventPublisher;
public MyLocalCacheVerifier(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void checkLocalCache() {
try {
// ...
}
catch (CacheCompletelyBrokenException ex) {
AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN);
}
}
}
import org.springframework.boot.availability.AvailabilityChangeEvent
import org.springframework.boot.availability.LivenessState
import org.springframework.context.ApplicationEventPublisher
import org.springframework.stereotype.Component
@Component
class MyLocalCacheVerifier(private val eventPublisher: ApplicationEventPublisher) {
fun checkLocalCache() {
try {
// ...
} catch (ex: CacheCompletelyBrokenException) {
AvailabilityChangeEvent.publish(eventPublisher, ex, LivenessState.BROKEN)
}
}
}
Spring Boot provides Kubernetes HTTP probes for "Liveness" and "Readiness" with Actuator Health Endpoints. You can get more guidance about deploying Spring Boot applications on Kubernetes in the dedicated section.
In general, the "Liveness" state should not be based on external checks, such as health checks. If it did, a failing external system (a database, a Web API, an external cache) would trigger massive restarts and cascading failures across the platform. |
Tasks expected to run during startup should be executed by CommandLineRunner and ApplicationRunner components instead of using Spring component lifecycle callbacks such as @PostConstruct .
|
Application Events and Listeners
In addition to the usual Spring Framework events, such as ContextRefreshedEvent
, a SpringApplication
sends some additional application events.
Some events are actually triggered before the If you want those listeners to be registered automatically, regardless of the way the application is created, you can add a
|
Application events are sent in the following order, as your application runs:
-
An
ApplicationStartingEvent
is sent at the start of a run but before any processing, except for the registration of listeners and initializers. -
An
ApplicationEnvironmentPreparedEvent
is sent when theEnvironment
to be used in the context is known but before the context is created. -
An
ApplicationContextInitializedEvent
is sent when theApplicationContext
is prepared and ApplicationContextInitializers have been called but before any bean definitions are loaded. -
An
ApplicationPreparedEvent
is sent just before the refresh is started but after bean definitions have been loaded. -
An
ApplicationStartedEvent
is sent after the context has been refreshed but before any application and command-line runners have been called. -
An
AvailabilityChangeEvent
is sent right after withLivenessState.CORRECT
to indicate that the application is considered as live. -
An
ApplicationReadyEvent
is sent after any application and command-line runners have been called. -
An
AvailabilityChangeEvent
is sent right after withReadinessState.ACCEPTING_TRAFFIC
to indicate that the application is ready to service requests. -
An
ApplicationFailedEvent
is sent if there is an exception on startup.
The above list only includes SpringApplicationEvent
s that are tied to a SpringApplication
.
In addition to these, the following events are also published after ApplicationPreparedEvent
and before ApplicationStartedEvent
:
-
A
WebServerInitializedEvent
is sent after theWebServer
is ready.ServletWebServerInitializedEvent
andReactiveWebServerInitializedEvent
are the servlet and reactive variants respectively. -
A
ContextRefreshedEvent
is sent when anApplicationContext
is refreshed.
You often need not use application events, but it can be handy to know that they exist. Internally, Spring Boot uses events to handle a variety of tasks. |
Event listeners should not run potentially lengthy tasks as they execute in the same thread by default. Consider using application and command-line runners instead. |
Application events are sent by using Spring Framework’s event publishing mechanism.
Part of this mechanism ensures that an event published to the listeners in a child context is also published to the listeners in any ancestor contexts.
As a result of this, if your application uses a hierarchy of SpringApplication
instances, a listener may receive multiple instances of the same type of application event.
To allow your listener to distinguish between an event for its context and an event for a descendant context, it should request that its application context is injected and then compare the injected context with the context of the event.
The context can be injected by implementing ApplicationContextAware
or, if the listener is a bean, by using @Autowired
.
Some events are actually triggered before the If you want those listeners to be registered automatically, regardless of the way the application is created, you can add a
|
You often need not use application events, but it can be handy to know that they exist. Internally, Spring Boot uses events to handle a variety of tasks. |
Event listeners should not run potentially lengthy tasks as they execute in the same thread by default. Consider using application and command-line runners instead. |
Web Environment
A SpringApplication
attempts to create the right type of ApplicationContext
on your behalf.
The algorithm used to determine a WebApplicationType
is the following:
-
If Spring MVC is present, an
AnnotationConfigServletWebServerApplicationContext
is used -
If Spring MVC is not present and Spring WebFlux is present, an
AnnotationConfigReactiveWebServerApplicationContext
is used -
Otherwise,
AnnotationConfigApplicationContext
is used
This means that if you are using Spring MVC and the new WebClient
from Spring WebFlux in the same application, Spring MVC will be used by default.
You can override that easily by calling setWebApplicationType(WebApplicationType)
.
It is also possible to take complete control of the ApplicationContext
type that is used by calling setApplicationContextFactory(…)
.
It is often desirable to call setWebApplicationType(WebApplicationType.NONE) when using SpringApplication within a JUnit test.
|
It is often desirable to call setWebApplicationType(WebApplicationType.NONE) when using SpringApplication within a JUnit test.
|
Accessing Application Arguments
If you need to access the application arguments that were passed to SpringApplication.run(…)
, you can inject a org.springframework.boot.ApplicationArguments
bean.
The ApplicationArguments
interface provides access to both the raw String[]
arguments as well as parsed option
and non-option
arguments, as shown in the following example:
-
Java
-
Kotlin
import java.util.List;
import org.springframework.boot.ApplicationArguments;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
public MyBean(ApplicationArguments args) {
boolean debug = args.containsOption("debug");
List<String> files = args.getNonOptionArgs();
if (debug) {
System.out.println(files);
}
// if run with "--debug logfile.txt" prints ["logfile.txt"]
}
}
import org.springframework.boot.ApplicationArguments
import org.springframework.stereotype.Component
@Component
class MyBean(args: ApplicationArguments) {
init {
val debug = args.containsOption("debug")
val files = args.nonOptionArgs
if (debug) {
println(files)
}
// if run with "--debug logfile.txt" prints ["logfile.txt"]
}
}
Spring Boot also registers a CommandLinePropertySource with the Spring Environment .
This lets you also inject single application arguments by using the @Value annotation.
|
Spring Boot also registers a CommandLinePropertySource with the Spring Environment .
This lets you also inject single application arguments by using the @Value annotation.
|
Using the ApplicationRunner or CommandLineRunner
If you need to run some specific code once the SpringApplication
has started, you can implement the ApplicationRunner
or CommandLineRunner
interfaces.
Both interfaces work in the same way and offer a single run
method, which is called just before SpringApplication.run(…)
completes.
This contract is well suited for tasks that should run after application startup but before it starts accepting traffic. |
The CommandLineRunner
interfaces provides access to application arguments as a string array, whereas the ApplicationRunner
uses the ApplicationArguments
interface discussed earlier.
The following example shows a CommandLineRunner
with a run
method:
-
Java
-
Kotlin
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) {
// Do something...
}
}
import org.springframework.boot.CommandLineRunner
import org.springframework.stereotype.Component
@Component
class MyCommandLineRunner : CommandLineRunner {
override fun run(vararg args: String) {
// Do something...
}
}
If several CommandLineRunner
or ApplicationRunner
beans are defined that must be called in a specific order, you can additionally implement the org.springframework.core.Ordered
interface or use the org.springframework.core.annotation.Order
annotation.
This contract is well suited for tasks that should run after application startup but before it starts accepting traffic. |
Application Exit
Each SpringApplication
registers a shutdown hook with the JVM to ensure that the ApplicationContext
closes gracefully on exit.
All the standard Spring lifecycle callbacks (such as the DisposableBean
interface or the @PreDestroy
annotation) can be used.
In addition, beans may implement the org.springframework.boot.ExitCodeGenerator
interface if they wish to return a specific exit code when SpringApplication.exit()
is called.
This exit code can then be passed to System.exit()
to return it as a status code, as shown in the following example:
-
Java
-
Kotlin
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class MyApplication {
@Bean
public ExitCodeGenerator exitCodeGenerator() {
return () -> 42;
}
public static void main(String[] args) {
System.exit(SpringApplication.exit(SpringApplication.run(MyApplication.class, args)));
}
}
import org.springframework.boot.ExitCodeGenerator
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import kotlin.system.exitProcess
@SpringBootApplication
class MyApplication {
@Bean
fun exitCodeGenerator() = ExitCodeGenerator { 42 }
}
fun main(args: Array<String>) {
exitProcess(SpringApplication.exit(
runApplication<MyApplication>(*args)))
}
Also, the ExitCodeGenerator
interface may be implemented by exceptions.
When such an exception is encountered, Spring Boot returns the exit code provided by the implemented getExitCode()
method.
If there is more than one ExitCodeGenerator
, the first non-zero exit code that is generated is used.
To control the order in which the generators are called, additionally implement the org.springframework.core.Ordered
interface or use the org.springframework.core.annotation.Order
annotation.
Admin Features
It is possible to enable admin-related features for the application by specifying the spring.application.admin.enabled
property.
This exposes the SpringApplicationAdminMXBean
on the platform MBeanServer
.
You could use this feature to administer your Spring Boot application remotely.
This feature could also be useful for any service wrapper implementation.
If you want to know on which HTTP port the application is running, get the property with a key of local.server.port .
|
If you want to know on which HTTP port the application is running, get the property with a key of local.server.port .
|
Application Startup tracking
During the application startup, the SpringApplication
and the ApplicationContext
perform many tasks related to the application lifecycle,
the beans lifecycle or even processing application events.
With ApplicationStartup
, Spring Framework allows you to track the application startup sequence with StartupStep
objects.
This data can be collected for profiling purposes, or just to have a better understanding of an application startup process.
You can choose an ApplicationStartup
implementation when setting up the SpringApplication
instance.
For example, to use the BufferingApplicationStartup
, you could write:
-
Java
-
Kotlin
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setApplicationStartup(new BufferingApplicationStartup(2048));
application.run(args);
}
}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args) {
applicationStartup = BufferingApplicationStartup(2048)
}
}
The first available implementation, FlightRecorderApplicationStartup
is provided by Spring Framework.
It adds Spring-specific startup events to a Java Flight Recorder session and is meant for profiling applications and correlating their Spring context lifecycle with JVM events (such as allocations, GCs, class loading…).
Once configured, you can record data by running the application with the Flight Recorder enabled:
$ java -XX:StartFlightRecording:filename=recording.jfr,duration=10s -jar demo.jar
Spring Boot ships with the BufferingApplicationStartup
variant; this implementation is meant for buffering the startup steps and draining them into an external metrics system.
Applications can ask for the bean of type BufferingApplicationStartup
in any component.
Spring Boot can also be configured to expose a startup
endpoint that provides this information as a JSON document.
Virtual threads
If you’re running on Java 21 or up, you can enable virtual threads by setting the property spring.threads.virtual.enabled
to true
.
Before turning on this option for your application, you should consider reading the official Java virtual threads documentation.
In some cases, applications can experience lower throughput because of "Pinned Virtual Threads"; this page also explains how to detect such cases with JDK Flight Recorder or the jcmd
CLI.
If virtual threads are enabled, properties which configure thread pools don’t have an effect anymore. That’s because virtual threads are scheduled on a JVM wide platform thread pool and not on dedicated thread pools. |
One side effect of virtual threads is that they are daemon threads.
A JVM will exit if all of its threads are daemon threads.
This behavior can be a problem when you rely on @Scheduled beans, for example, to keep your application alive.
If you use virtual threads, the scheduler thread is a virtual thread and therefore a daemon thread and won’t keep the JVM alive.
This not only affects scheduling and can be the case with other technologies too.
To keep the JVM running in all cases, it is recommended to set the property spring.main.keep-alive to true .
This ensures that the JVM is kept alive, even if all threads are virtual threads.
|
If virtual threads are enabled, properties which configure thread pools don’t have an effect anymore. That’s because virtual threads are scheduled on a JVM wide platform thread pool and not on dedicated thread pools. |
One side effect of virtual threads is that they are daemon threads.
A JVM will exit if all of its threads are daemon threads.
This behavior can be a problem when you rely on @Scheduled beans, for example, to keep your application alive.
If you use virtual threads, the scheduler thread is a virtual thread and therefore a daemon thread and won’t keep the JVM alive.
This not only affects scheduling and can be the case with other technologies too.
To keep the JVM running in all cases, it is recommended to set the property spring.main.keep-alive to true .
This ensures that the JVM is kept alive, even if all threads are virtual threads.
|