Whenever you need, to perform a specific task once after all the Spring Beans are created and the Application Context has been created then you can implement ApplicationRunner or CommandLineRunner interface. Both the interfaces works the same way and has a single run() method. A similar implementation is already there in Spring and many people would have known it JobLauncherCommandLineRunner which is used for running jobs in Spring Batch.
Spring Boot CommandLineRunner and ApplicationRunner
Folder Structure:
- Create a simple Maven Project “SpringBootTutorial” by selecting maven-archetype-quickstart and create a package for our source files “com.javainterviewpoint” under src/main/java
- Now add the following dependency in the POM.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.javainterviewpoint</groupId> <artifactId>SpringBootTutorial</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.1.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
- Create the Java classes HelloWorld.java and HelloCommandLineRunner.java under com.javainterviewpoint folder.
The spring-boot-starter-parent is a special starter, it provides useful Maven defaults. Since we are developing a web application, we also need to add spring-boot-starter-web dependency.This will additional dependencies such Tomcat, Jackson, Spring boot etc which are required for our application.
HelloCommandLinerRunner.java
package com.javainterviewpoint; import java.util.Arrays; import org.springframework.boot.CommandLineRunner; public class HelloCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { if(args.length > 0) System.out.println("Spring Boot Hello World Application Command Line Arguments passed : "+Arrays.toString(args)); else System.out.println("No Command Line Arguments passed"); } }
CommandLineRunner interface has an unimplemented run() method, In our HelloCommandLinerRunner class we have implemented the CommandLineRunner interface and have overridden the run() method. So when the SpringApplication.run() of the HelloWorld class starts the spring boot application just before the application gets started, CommandLineRunner.run() will be executed. The run() method of CommandLineRunner accepts the arguments which are passed as Command Line arguments.
HelloWorld.java
Place HelloWorld.java under com.javainterviewpoint folder
package com.javainterviewpoint; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.support.SpringBootServletInitializer; import org.springframework.context.annotation.Bean; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @EnableAutoConfiguration public class HelloWorld extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(HelloWorld.class); } @Bean public HelloCommandLineRunner helloRunner() { return new HelloCommandLineRunner(); } public static void main(String[] args) throws Exception { SpringApplication.run(HelloWorld.class, args); } @RequestMapping("/") String hello() { return "Hello World! JavaInterviewPoint2222222"; } }
We have added the below annotations in our HelloWorld class
- @RestController – This annotation is a stereotype annotation, this annotation tells spring to render the result back to the caller.
- @RequestMapping – This annotation will any HTTP request with the path “/” should be mapped to the hello() method
- @EnableAutoConfiguration – This annotation tells the Spring Boot to configure the application based on the dependencies added. Since spring-boot-starter-web has added Tomcat and Spring MVC, auto-configuration will setup a web based application.
- @Bean – This annotation will make our HelloCommandLineRunner act as a bean.
Our main() method is the triggering point of our java application, it in-turn calls Spring Boot’s SpringApplication class run() method which bootstrap our HelloWorld application and starts the tomcat server. We need to pass our HelloWorld.class as an argument to our run() method.
Console
D:\sts-3.8.3.RELEASE\Workspace\SpringBootTutorial\target>java -jar SpringBootTutorial-0.0.1-SNAPSHOT.jar Param1 Param2 . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.5.1.RELEASE) 2017-03-19 18:46:35.666 INFO 4868 --- [ main] com.javainterviewpoint.HelloWorld : Starting HelloWorld v0.0.1-SNAPSHOT on Jack-PC with PID 4868 (D:\sts-3.8.3.RELEASE\Workspace\SpringBootTutorial\target\SpringBootTutorial-0.0.1-SNAPSHOT.jar started by Jack in D:\sts-3.8.3.RELEASE\Workspace\SpringBootTutorial\target) 2017-03-19 18:46:35.671 INFO 4868 --- [ main] com.javainterviewpoint.HelloWorld : No active profile set, falling back to default profiles: default 2017-03-19 18:46:35.751 INFO 4868 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1906a77: startup date [Sun Mar 19 18:46:35 IST 2017]; root of context hierarchy 2017-03-19 18:46:37.037 INFO 4868 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration' of type [class org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2017-03-19 18:46:37.206 INFO 4868 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'validator' of type [class org.springframework.validation.beanvalidation.LocalValidatorFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2017-03-19 18:46:37.839 INFO 4868 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http) 2017-03-19 18:46:37.856 INFO 4868 --- [ main] o.apache.catalina.core.StandardService : Starting service Tomcat 2017-03-19 18:46:37.858 INFO 4868 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.11 2017-03-19 18:46:37.986 INFO 4868 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2017-03-19 18:46:37.987 INFO 4868 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2238 ms 2017-03-19 18:46:38.201 INFO 4868 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/] 2017-03-19 18:46:38.206 INFO 4868 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'errorPageFilter' to: [/*] 2017-03-19 18:46:38.207 INFO 4868 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] 2017-03-19 18:46:38.207 INFO 4868 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] 2017-03-19 18:46:38.207 INFO 4868 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] 2017-03-19 18:46:38.207 INFO 4868 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] 2017-03-19 18:46:38.646 INFO 4868 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1906a77: startup date [Sun Mar 19 18:46:35 IST 2017]; root of context hierarchy 2017-03-19 18:46:38.763 INFO 4868 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto java.lang.String com.javainterviewpoint.HelloWorld.hello() 2017-03-19 18:46:38.769 INFO 4868 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 2017-03-19 18:46:38.769 INFO 4868 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) 2017-03-19 18:46:38.824 INFO 4868 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2017-03-19 18:46:38.824 INFO 4868 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2017-03-19 18:46:38.886 INFO 4868 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2017-03-19 18:46:39.106 INFO 4868 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup 2017-03-19 18:46:39.185 INFO 4868 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http) Spring Boot Hello World Application Command Line Arguments passed : [Param1, Param2] 2017-03-19 18:46:39.191 INFO 4868 --- [ main] com.javainterviewpoint.HelloWorld : Started HelloWorld in 4.14 seconds (JVM running for 4.696)
@Order Annotation Spring Boot
Whenever you have more than one class implementing the CommandLineRunner / ApplicationRunner, then you can use the @Order annotation mention which run() method has to be executed first. Let’s look into the below example.
package com.javainterviewpoint; import org.springframework.boot.CommandLineRunner; import org.springframework.core.annotation.Order; @Order(1) public class NewHelloCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("New Hello Command Line Runner called"); } } package com.javainterviewpoint; import org.springframework.boot.CommandLineRunner; import org.springframework.core.annotation.Order; @Order(2) public class HelloCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("Old Hello Command Line Runner called"); } }
Now our NewHelloCommandLineRunner run() method will be executed first as we have mentioned order as “1”.
Difference between CommandLineRunner and ApplicationRunner
Both of them provides the same functionality and the only difference between CommandLineRunner and ApplicationRunner is CommandLineRunner.run() accepts String array[] whereas ApplicationRunner.run() accepts ApplicationArguments as argument.
Leave a Reply