Back to Spring Boot Course

Spring Boot Course

Often there is a need to execute certain business logic at servlet container startup for e.g. fetching feeds from a remote service, sending a notification about app startup by email, etc.

Spring boot provides two main mechanisms for wiring app startup code. This code will be executed once spring context has been loaded and servlet container is ready to serve requests.

  • Using PostConstruct Annotation
  • Using CommandLineRunner Interface
  • Using ApplicationRunner Interface

Lets see how to use PostConstruct

  • Runs after dependency injection is done, but before the application is fully started.
  • Useful for initialization logic that doesn't depend on the full Spring Boot lifecycle.
  • Limitation: Doesn't wait for the application to be fully ready; no access to command-line arguments.
package com.praveen.runner; import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component @Slf4j public class MyBean { @PostConstruct public void init() { log.info("PostConstruct: Bean is initialized"); } }

Lets see how to use CommandLineRunner

CommandLineRunner is a simple Spring Boot interface with a run method. Spring Boot will automatically call the run method of all beans implementing this interface after the application context has been loaded.

Running more than one ApplicationRunner or CommandLineRunner in predefined order

We can use @Order(<sequence>) annotation to each ApplicationRunner Bean to run them in specified order.

MyCommandLineRunner class

package com.praveen.runner; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.CommandLineRunner; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /*CommandLineRunner with Order Annotation*/ @Component @Order(1) @Slf4j public class MyCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { log.info("In MyCommandLineRunner Class"); } }

MyApplicationRunner class

package com.praveen.runner; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; /*ApplicationRunner with Order Annotation*/ @Configuration @Order(2) @Slf4j public class MyApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { log.info("In MyApplicationRunner Class"); } }

RunnerApp Main class

package com.praveen.runner; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @Slf4j public class RunnerApp { public static void main(String[] args) { SpringApplication.run(RunnerApp.class); log.info("In RunnerApp Main Class"); } }

Let's see the console ouput

2025-06-23T14:53:02.824+05:30 INFO 14916 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 9092 (http) 2025-06-23T14:53:02.898+05:30 INFO 14916 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2025-06-23T14:53:02.899+05:30 INFO 14916 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.41] 2025-06-23T14:53:03.155+05:30 INFO 14916 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2025-06-23T14:53:03.159+05:30 INFO 14916 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 4414 ms 2025-06-23T14:53:03.637+05:30 INFO 14916 --- [ main] com.praveen.runner.MyBean : PostConstruct: Bean is initialized 2025-06-23T14:53:04.740+05:30 INFO 14916 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 9092 (http) with context path '/' 2025-06-23T14:53:04.783+05:30 INFO 14916 --- [ main] com.praveen.runner.RunnerApp : Started RunnerApp in 8.098 seconds (process running for 9.165) 2025-06-23T14:53:04.800+05:30 INFO 14916 --- [ main] com.praveen.runner.MyCommandLineRunner : In MyCommandLineRunner Class 2025-06-23T14:53:04.801+05:30 INFO 14916 --- [ main] com.praveen.runner.MyApplicationRunner : In MyApplicationRunner Class 2025-06-23T14:53:04.818+05:30 INFO 14916 --- [ main] com.praveen.runner.RunnerApp : In RunnerApp Main Class

Note: Bean with Order 1 will execute before bean with Order 2.

Notice that the run method is called after application context is loaded but before the execution of the main method is complete.

Most console applications will only have a single class that implements CommandLineRunner. If your application has multiple classes that implement CommandLineRunner, the order of execution can be specified using Spring's @Order annotation.

If we configure both Runner but not implements Ordered then by default Annotation based Configuration will be executed first.

Working process of CommandLineRunner and ApplicationRunner are same, but CommandLineRunner (CLR) holds data in String[] format where as Application (AR) holds data as ApllicationArguments as Option/Non-Option format.

PostConstruct vs ApplicationRunner

Spring provides @PostConstruct annotation that can be used for post initialization work on a give component. But @PostConstruct method is invoked after the component has been created by spring container and before entire Spring context have been initialized.

On the other hand ApplicationRunner code will only run once the entire spring context have been initialized.

Fetch Data from properties file

application.properties or application.yml is a primary source input to spring boot (Spring Container).

application.properties

  • It holds in key=value format
  • Keys are two types
  1. Spring Boot defined (Predefined) Reference Link

  2. Programmer defined

Let's see an example

application.properties

system.product.id= 1 system.product.name= Walmart Credit Card system.product.description= We provide customized walmart credit cards to customers system.product.code= WCC

Note:

  • Allowed special symbol are dot(.), dash(-) and underscore (_).
  • Key=value both are String type, Spring supports both are String type, Spring supports type conversation (ex String->int) automatically.
  • To read one key-value in code use Legacy syntax : @Value("key")
package com.praveen.runner; import lombok.Getter; import lombok.Setter; import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; @Component @Slf4j @Getter @Setter @ToString public class MyCommandLineRunnerWithInputDataUsingValueAnnotation implements CommandLineRunner { @Value("${system.product.id}") private int prodId; @Value("${system.product.name}") private String prodName; @Value("${system.product.description}") private String prodDesc; @Value("${system.product.code}") private String prodCode; public void run(String... args) throws Exception { log.info("In public class MyCommandLineRunnerWithInputDataUsingValueAnnotation implements CommandLineRunner {\n Class @Value Annotation {}", this); } }

Let's see the console output

2025-06-23T14:53:04.807+05:30 INFO 14916 --- [ main] tRunnerWithInputDataUsingValueAnnotation : In SpringBootRunnerWithInputDataUsingValueAnnotation Class @Value Annotation SpringBootRunnerWithInputDataUsingValueAnnotation(prodId=1, prodName=Walmart Credit Card, prodDesc=We provide customized walmart credit cards to customers, prodCode=WCC)

Note: If key data is mismatched with variable data type, then Spring Container throws Exception : TypeMistchException : Failed to convert value.

We can also use Environment Object or @ConfigurationProperties to fetch the values from application.properties

Using Environment Object

package com.praveen.runner; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.CommandLineRunner; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @Component @Slf4j @AllArgsConstructor public class MyCommandLineRunnerWithInputDataUsingEnv implements CommandLineRunner { private final Environment env; @Override public void run(String... args) throws Exception { // Retrieve properties from environment with default values if not found String productId = env.getProperty("system.product.id", "N/A"); String productName = env.getProperty("system.product.name", "N/A"); String productDescription = env.getProperty("system.product.description", "N/A"); String productCode = env.getProperty("system.product.code", "N/A"); log.info( "In MyCommandLineRunnerWithInputDataUsingEnv Class Using Environment Id {} name {} description {} code {}", productId, productName, productDescription, productCode); } }

Let's see the console output

2025-06-23T14:53:04.802+05:30 INFO 14916 --- [ main] .r.SpringBootRunnerWithInputDataUsingEnv : In SpringBootRunnerWithInputDataUsingEnv Class Using Environment Id 1 name Walmart Credit Card description We provide customized walmart credit cards to customers code WCC

Using @ConfigurationProperties Annotation

package com.praveen.runner; import lombok.Getter; import lombok.Setter; import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component @ConfigurationProperties("system.product") @Slf4j @Getter @Setter @ToString public class MyCommandLineRunnerWithInputDataUsingConfigurationProperties implements CommandLineRunner { private int id; private String name; private String description; private String code; public void run(String... args) throws Exception { log.info("In MyCommandLineRunnerWithInputDataUsingConfigurationProperties Class @ConfigurationProperties Annotation {}", this); } }
2025-06-23T14:53:04.815+05:30 INFO 14916 --- [ main] ithInputDataUsingConfigurationProperties : In SpringBootRunnerWithInputDataUsingConfigurationProperties Class @ConfigurationProperties Annotation SpringBootRunnerWithInputDataUsingConfigurationProperties(id=1, name=Walmart Credit Card, description=We provide customized walmart credit cards to customers, code=WCC)

Here with the complete code for your reference.