Spring / Spring boot: Difference between CommandLineRunner and ApplicationRunner
Requisite: Some basic knowledge for Spring Boot and Gradle.
Both interfaces, CommandLineRunner and ApplicationRunner works in the same way and offer a single run method.
The difference is, the CommandLineRunner interface provides access to the application arguments as a simple String array, while ApplcationRunner uses the ApplicationArguments interface, which provides access to both the raw String[] arguments as well as parsed option and non-option arguments.
Using CommandLineRunner.
package net.javapedia.springboot; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; public class SpringBootAppCommandLineRunner implements CommandLineRunner { private static Logger logger = LoggerFactory.getLogger (SpringBootAppCommandLineRunner.class); public static void main(String[] args) { logger.debug("Main started."); SpringApplication.run (SpringBootAppCommandLineRunner.class, args); logger.debug("Main completed."); } @Override public void run(String... args) throws Exception { logger.info("Run executed."); for (String item: args) { logger.info(" args : {}", item); } } }
Output:
4:57:34 PM: Executing task 'SpringBootAppCommandLineRunner.main()'... > Task :compileJava UP-TO-DATE > Task :processResources NO-SOURCE > Task :classes UP-TO-DATE > Task :SpringBootAppCommandLineRunner.main() 16:57:36.151 [main] DEBUG net.javapedia.springboot.SpringBootAppCommandLineRunner - Main started. . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.9.RELEASE) 2019-10-13 16:57:36.962 INFO 7456 --- [ main] n.j.s.SpringBootAppCommandLineRunner : Starting SpringBootAppCommandLineRunner on Home-PC with PID 7456 (C:\Users\Owner\Downloads\akka-quickstart-java\Spring-boot-Examples\build\classes\java\main started by Owner in C:\Users\Owner\Downloads\akka-quickstart-java\Spring-boot-Examples) 2019-10-13 16:57:36.966 INFO 7456 --- [ main] n.j.s.SpringBootAppCommandLineRunner : No active profile set, falling back to default profiles: default 2019-10-13 16:57:37.123 INFO 7456 --- [ main] n.j.s.SpringBootAppCommandLineRunner : Started SpringBootAppCommandLineRunner in 0.787 seconds (JVM running for 1.352) 2019-10-13 16:57:37.125 INFO 7456 --- [ main] n.j.s.SpringBootAppCommandLineRunner : Run executed. 2019-10-13 16:57:37.126 INFO 7456 --- [ main] n.j.s.SpringBootAppCommandLineRunner : args : -pArg=1 2019-10-13 16:57:37.127 INFO 7456 --- [ main] n.j.s.SpringBootAppCommandLineRunner : args : -pArg2=2 2019-10-13 16:57:37.127 INFO 7456 --- [ main] n.j.s.SpringBootAppCommandLineRunner : args : --pArg3=3 2019-10-13 16:57:37.127 INFO 7456 --- [ main] n.j.s.SpringBootAppCommandLineRunner : args : pArg4=4 Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0. Use '--warning-mode all' to show the individual deprecation warnings. See https://docs.gradle.org/5.2.1/userguide/command_line_interface.html#sec:command_line_warnings BUILD SUCCESSFUL in 2s 2 actionable tasks: 1 executed, 1 up-to-date 4:57:37 PM: Task execution finished 'SpringBootAppCommandLineRunner.main()'.
You may observe that the program arguments are parsed and printed however the VM argument is missing with the CommandLineRunner.
Using ApplicationRunner.
package net.javapedia.springboot; import org.slf4j.ILoggerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.boot.SpringApplication; public class SpringBootApplicationRunner implements ApplicationRunner { private static Logger logger = LoggerFactory.getLogger(SpringBootApplicationRunner.class); @Override public void run(final ApplicationArguments args) throws Exception { logger.info(" Total NonOptionArgs: {}", args.getNonOptionArgs().size()); args.getNonOptionArgs().forEach( logger::info); logger.info(" Totla OptionArgs: {}", args.getOptionNames().size()); args.getOptionNames().forEach(name -> logger.info("{} = {}",name, args.getOptionValues(name))); } public static void main(String[] args) { SpringApplication.run(SpringBootApplicationRunner.class, args); } }
You can see that ApplicationRunner can parse NonOptionArgs and OptionArgs:
- When you pass --optionName=optionValue as program arguments, then the optionName is recognized as an optionArgs,
- otherwise they are parsed as NonOptionArgs.
If I pass --pArg3=3,2,1,0 as the Program arguments, an optionArg will be crated with the name pArg3 and option Values will return an List< String> .
2019-10-13 18:43:51.648 INFO 10408 --- [ main] n.j.s.SpringBootApplicationRunner : pArg4=4 2019-10-13 18:43:51.648 INFO 10408 --- [ main] n.j.s.SpringBootApplicationRunner : Totla OptionArgs: 1 2019-10-13 18:43:51.649 INFO 10408 --- [ main] n.j.s.SpringBootApplicationRunner : pArg3 = [3,2,1,0]