Spring boot offers multiple options, for executing your code during the application startup. This post covers some of the ‘out of the box’ practices recommended by the Spring developers.
The @SpringBootApplication
The SpringApplication class provides a convenient way to bootstrap a Spring application that is started from a main() method. This is what a typical Spring boot application looks like:
@Slf4j @SpringBootApplication public class KitchenSinkApplication { public static void main(String[] args) { SpringApplication.run(KitchenSinkApplication.class, args); } }
When your application starts, you should see something similar to the following output:
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.6.6) 2022-04-15 09:09:18.318 INFO 69832 --- [ main] c.e.k.demo.KitchenSinkApplication : Starting KitchenSinkApplication using Java 11.0.11 on neel.local with PID 69832 (/Users/Neel/spring-boot-examples/run-on-startup/build/classes/java/main started by p7111831 in /Users/Neel/spring-boot-examples/run-on-startup) 2022-04-15 09:09:18.321 INFO 69832 --- [ main] c.e.k.demo.KitchenSinkApplication : No active profile set, falling back to 1 default profile: "default" 2022-04-15 09:09:18.984 INFO 69832 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2022-04-15 09:09:18.991 INFO 69832 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2022-04-15 09:09:18.991 INFO 69832 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.60] 2022-04-15 09:09:19.060 INFO 69832 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2022-04-15 09:09:19.060 INFO 69832 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 700 ms 2022-04-15 09:09:19.333 INFO 69832 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2022-04-15 09:09:19.342 INFO 69832 --- [ main] c.e.k.demo.KitchenSinkApplication : Started KitchenSinkApplication in 1.27 seconds (JVM running for 2.083)
Option-1: @PostConstruct Annotation
You can add @PostConstruct to your main class or to a @Component of your application to execute the code after your application is started.
@PostConstruct is mainly used to complete the initialization of your application. It is part of the Spring Boot Lifecycle.
If you want to execute some long-running tasks, you should avoid this approach.
@Slf4j @SpringBootApplication public class KitchenSinkApplication { public static void main(String[] args) { SpringApplication.run(KitchenSinkApplication.class, args); } @PostConstruct public void init() { log.info("Executes after beans are instantiated"); } }
Option-2: ApplicationRunner interface
ApplicationRunner or CommandLineRunner is the recommended method if you have to execute some code after the initialization of the application.
You could implement the ApplicationRunner in your main class too, but it’s recommended to separate the code in a dedicated class.
@Slf4j @Component public class MyApplicationRunner1 implements ApplicationRunner { @Override public void run(ApplicationArguments args) { log.info("Executed runner1"); } }
You could have multiple ApplicationRunner implementations in your code. But where there are multiple runners, spring doesn’t know which order they should execute.
To sort the runners you can use @Order(1)
annotation.
For eg, my MyApplicationRunner2 looks something like this.
import lombok.extern.slf4j.Slf4j; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Slf4j @Component @Order(2) public class MyApplicationRunner2 implements ApplicationRunner { @Override public void run(ApplicationArguments args) { log.info("Executed runner1"); } }
Option-3: ApplicationReadyEvent
Spring boot publishes an event (ApplicationReadyEvent) to indicate that the application is ready to service requests. At this point, all the initialization steps have been completed by then.
@Slf4j @Component public class ApplicationStartEvent { @EventListener(ApplicationReadyEvent.class) public void onReadyEvent() { log.info("Executes when the application is ready"); } }
Now if we run all three approaches together, this is what the output looks like.
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.6.6) 2022-04-15 09:30:34.578 INFO 81196 --- [ main] c.e.k.demo.KitchenSinkApplication : Starting KitchenSinkApplication using Java 11.0.11 on neel.local with PID 81196 (/Users/Neel/spring-boot-examples/run-on-startup/build/classes/java/main started by p7111831 in /Users/Neel/spring-boot-examples/run-on-startup) 2022-04-15 09:30:34.582 INFO 81196 --- [ main] c.e.k.demo.KitchenSinkApplication : No active profile set, falling back to 1 default profile: "default" 2022-04-15 09:30:35.238 INFO 81196 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2022-04-15 09:30:35.246 INFO 81196 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2022-04-15 09:30:35.246 INFO 81196 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.60] 2022-04-15 09:30:35.312 INFO 81196 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2022-04-15 09:30:35.313 INFO 81196 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 687 ms 2022-04-15 09:30:35.347 INFO 81196 --- [ main] c.e.k.demo.KitchenSinkApplication : Executes after beans are instantiated 2022-04-15 09:30:35.632 INFO 81196 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2022-04-15 09:30:35.632 INFO 81196 --- [ main] c.e.k.demo.KitchenSinkApplication : Started KitchenSinkApplication in 1.974 seconds (JVM running for 2.86) 2022-04-15 09:30:35.632 INFO 81196 --- [ main] c.e.k.demo.MyApplicationRunner1 : Executed runner1 2022-04-15 09:30:35.632 INFO 81196 --- [ main] c.e.k.demo.MyApplicationRunner2 : Executed runner2 2022-04-15 09:30:35.632 INFO 81196 --- [ main] c.e.k.demo.ApplicationStartEvent : Executes when application is ready
Download Project on Github
Check out the complete source code for this example here on Github.