1. The purpose of this post

I would demo the difference between CommandLineRunner and ApplicationRunner in Spring Boot.

2. Environments

  • springboot 1.x and 2.x

3. What is the difference between CommandLineRunner and ApplicationRunner in Spring Boot.

3.1 The question

Sometimes, we want to run some specific code when springboot app starts,there are two ways to do this job via CommandLineRunner and ApplicationRunner, you can follow this article to have a test. But what’s the difference between these two interface, and why do the fellows of Spring supply both of them instead of one of them?

3.2 Test the CommandLineRunner

We can test the below codes with these command in IntelliJ IDEA: We set VM options and program parameters in IntelliJ IDEA’s run configurations like this:

spring boot arguments

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
public class MyCommand implements CommandLineRunner {
    private static Logger logger = LoggerFactory.getLogger(MyCommand.class);

    @Override
    public void run(String... strings) throws Exception {
        logger.info("MyCommand run");

        Arrays.stream(strings).forEach(s->logger.info("command arg {}",s)); //print all arguments
    }
}

Run the code ,The real java command is:

java -Dk1=v1 ... com.test.sb1jt.MainApp k2=v2 -k3=v3 --k4=v4

VM options are passed to java, and program parameters are passed to our main class.

After run we got this result:

2019-05-22 11:20:20.668  INFO 22646 --- [           main] com.test.sb1jt.commands.MyCommand        : MyCommand run
2019-05-22 11:20:20.671  INFO 22646 --- [           main] com.test.sb1jt.commands.MyCommand        : command arg k2=v2
2019-05-22 11:20:20.672  INFO 22646 --- [           main] com.test.sb1jt.commands.MyCommand        : command arg -k3=v3
2019-05-22 11:20:20.673  INFO 22646 --- [           main] com.test.sb1jt.commands.MyCommand        : command arg --k4=v4

You can see that only program arguments are parsed by CommandLineRunner, and the VM options are not parsed.

3.3 Test the ApplicationRunner

Use the above run configurations ,and we run the code below to test the ApplicationRunner:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

/**
 * Created on 2019/5/22.
 */
@Component
public class MyAppRunner implements ApplicationRunner {
    private static Logger logger = LoggerFactory.getLogger(MyAppRunner.class);

    @Override
    public void run(ApplicationArguments args) throws Exception {
        logger.info("MyAppRunner run");

        logger.info("# NonOptionArgs: " + args.getNonOptionArgs().size());

        logger.info("NonOptionArgs:");
        args.getNonOptionArgs().forEach(a->logger.info(a));

        logger.info("# OptionArgs: " + args.getOptionNames().size());
        logger.info("OptionArgs:");

        args.getOptionNames().forEach(optionName -> {
            logger.info(optionName + "=" + args.getOptionValues(optionName));
        });
    }
}

You can see that ApplicationRunner can parse NonOptionArgs and OptionArgs, the difference is as follows:

  • When you pass –optionName=optionValue as program arguments, then the optionName is recognized as an option
  • If you pass program arguments whose format is not –key=value, then they are parsed as NonOptionArgs

The real java command is:

java -Dk1=v1 ... com.test.sb1jt.MainApp k2=v2 -k3=v3 --k4=v4

We run the above code and got this:

2019-05-22 11:51:02.919  INFO 23021 --- [           main] com.test.sb1jt.commands.MyAppRunner      : MyAppRunner run
2019-05-22 11:51:02.919  INFO 23021 --- [           main] com.test.sb1jt.commands.MyAppRunner      : # NonOptionArgs: 2
2019-05-22 11:51:02.919  INFO 23021 --- [           main] com.test.sb1jt.commands.MyAppRunner      : NonOptionArgs:
2019-05-22 11:51:02.920  INFO 23021 --- [           main] com.test.sb1jt.commands.MyAppRunner      : k2=v2
2019-05-22 11:51:02.920  INFO 23021 --- [           main] com.test.sb1jt.commands.MyAppRunner      : -k3=v3
2019-05-22 11:51:02.920  INFO 23021 --- [           main] com.test.sb1jt.commands.MyAppRunner      : # OptionArgs: 1
2019-05-22 11:51:02.920  INFO 23021 --- [           main] com.test.sb1jt.commands.MyAppRunner      : OptionArgs:
2019-05-22 11:51:02.920  INFO 23021 --- [           main] com.test.sb1jt.commands.MyAppRunner      : k4=[v4]

You can see that, k2 and k3 are parsed as NonOptionArgs ,and k4 is parsed as OptionArg, because we defined it as –k4=v4.

4. Conclusion

We can see that the CommandLineRunner is simpler ,but ApplicationRunner is more sophisticated in parsing the program arguments.