🏠 ❯ Spring Boot ❯ Command Line Runner in Spring Boot.

Command Line Runner in Spring Boot.

In this post, We will take a look at Command line runner in Spring Boot and how to implement them properly with an example.

Typical Java Implementation

Let’s take a small example in pure java.

public class Adder {
    public static void main(String[] args) {
        int a = Integer.parseInt(args[0]);
        int b = Integer.parseInt(args[1]);
        System.out.println(a + b);
    }
}Code language: JavaScript (javascript)

The above class is an example of a command line application. The application takes two command line arguments, then calculates their sum and prints it after that the application exits. But the real world command line applications can be quite complex. This is where spring boot’s CommandLineRunner interface comes into the picture.

Implementing CommandLineRunner

For this example, I created a project from Spring Initializer without any dependencies. But the code will work along with any Spring Boot Starter. If you have done this correctly, the pom.xml should only contain spring-boot-starter as a dependency (and the boilerplate for test dependencies). When we run this empty project, You will see the spring example application booting up and dying just after few moments. At this point, the project is useless. Let’s make this application print hello world by implementing CommandLineRunner as shown below.

@SpringBootApplication
public class CommandlineApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(CommandlineApplication.class, args);
    }

    @Override
    public void run(String... args) {
        System.out.println("Hello World!");
    }
}Code language: JavaScript (javascript)

The above code prints Hello World at the end of the log output.

Here is how it works. The auto-configuration looks for any CommandLineRunner component in the classpath and calls the run(String[]) method. This would allow the components that implement CommandLineRunner to have access to the application context as well as the application parameters. For example, You can print all the beans in the current context as shown below.

@SpringBootApplication
public class CommandlineApplication implements CommandLineRunner {

    Logger logger = LoggerFactory.getLogger(CommandlineApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(CommandlineApplication.class, args);
    }

    @Autowired
    ApplicationContext applicationContext;

    @Override
    public void run(String... args) {
        Map<String, Object> beansOfType = applicationContext.getBeansOfType(Object.class);
        beansOfType.forEach((s, o) -> {
            logger.info("{} - {}", s, o.getClass());
        });
    }
}Code language: JavaScript (javascript)

Just try to run the above code yourself, and you will see the results.

Making use of Command-line Arguments

You may wonder why we can’t achieve the same with a @PostConstruct or an @EventListener(ApplicationReadyEvent.class) annotation. Events and PostConstruct methods does not have access to the command-line arguments. This is the reason why CommandLineRunner exists. This example lets you list all the beans that has a bean name containing a search text from commandline.

@SpringBootApplication
public class CommandlineApplication implements CommandLineRunner {

    Logger logger = LoggerFactory.getLogger(CommandlineApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(CommandlineApplication.class, args);
    }

    @Autowired
    ApplicationContext applicationContext;

    @Override
    public void run(String... args) {
        if (args.length > 0) {
            Map<String, Object> beansOfType = applicationContext.getBeansOfType(Object.class);
            beansOfType.forEach((s, o) -> {
                if (o.getClass().getCanonicalName().contains(args[0])) {
                    logger.info("{} - {}", s, o.getClass());
                }
            });
        }

    }
}Code language: JavaScript (javascript)

Calling the application with a commandline argument Log prints out only the following two lines in the log.

springBootLoggingSystem - class org.springframework.boot.logging.logback.LogbackLoggingSystem
springBootLoggerGroups - class org.springframework.boot.logging.LoggerGroupsCode language: CSS (css)

Command Line Runner as components

So it is clear why this command line runner interface exists as part of spring boot. We should use CommandLineRunner if we want to initiate any process that needs both the autowiring capabilities of the spring context and the application parameters.

One thing to note here is that I made my main class to implement CommandLineRunner. However, It is not advisable nor necessary. You can define your own component that extends the interface, and it should be fine. For example, the below works too.

@Component
public class HelloWorldCommandLineRunner  implements CommandLineRunner {
Logger logger = LoggerFactory.getLogger(CommandlineApplication.class);

    @Override
    public void run(String... args) throws Exception {
        logger.info("Hello world from command line runner");
    }
}Code language: JavaScript (javascript)

Multiple CommandLineRunners

You can also define multiple CommandLineRunner Implementations. The only catch here is that each of these components will run in series. If one of them is going to run for long, then the other runners will suffer. Also, the default Spring behaviour for beans of same type is that they are sorted by bean name in alphabetical order. So you may see the execution of components in the same order.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *