How to execute a piece of logic immediately after the Spring Boot application starts

1. Preface

I don't know if you've received this requirement, so just execute some logic when the project starts.For example, simple cache preheating, or broadcasting after going online, and so on.If you use the Spring Boot framework, you can do so with its interfaces CommandLineRunner and ApplicationRunner.

2. CommandLineRunner

org.springframework.boot.CommandLineRunner is an interface provided by Spring Boot, and when you implement it and inject it into the Spring IoC container, the Spring Boot application will execute its run method when it starts.A Spring Boot can have multiple implementations of CommandLineRunner, and when there are multiple implementations, you can implement the Ordered interface to control the order in which these implementations execute (the higher the Order value, the lower the priority).Next, let's declare the two implementations and specify the order:

Priority implementation:

package cn.felord;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

/**
 * Highest priority
 * This class expects the first sequential execution after springboot starts
 * @author felord.cn
 * @since 12:57
 **/
@Slf4j
@Component
public class HighOrderCommandLineRunner implements CommandLineRunner, Ordered {
    @Override
    public void run(String... args) throws Exception {
        for (String arg : args) {
            log.info("arg = " + arg);
        }
        log.info("i am highOrderRunner");
    }

    @Override
    public int getOrder() {
        return Integer.MIN_VALUE+1;
    }
}

Execute in the second order:

package cn.felord;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

/**
 * Priority is lower than {@code HighOrderCommandLineRunner}
 * @author felord.cn
 * @since 12:59
 **/
@Slf4j
@Component
public class LowOrderCommandLineRunner implements CommandLineRunner, Ordered {

    @Override
    public void run(String... args) throws Exception {
        log.info("i am lowOrderRunner");
    }

    @Override
    public int getOrder() {
        return Integer.MIN_VALUE+1;
    }
}

After the Spring Boot application is started, the console prints the results in a predetermined order:

2020-05-30 23:11:03.685  INFO 11976 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-05-30 23:11:03.701  INFO 11976 --- [           main] c.f.Application  : Started SpringBootApplication in 4.272 seconds (JVM running for 6.316)
2020-05-30 23:11:03.706  INFO 11976 --- [           main] c.f.HighOrderCommandLineRunner   : i am highOrderRunner
2020-05-30 23:11:03.706  INFO 11976 --- [           main] c.f.LowOrderCommandLineRunner   : i am lowOrderRunner

3. ApplicationRunner

In Spring Boot 1.3.0, another interface, ApplicationRunner, was introduced, which has the same functionality as CommandLineRunner.CommandLineRunner receives a variable parameter String... args, while ApplicationRunner receives an encapsulated object parameter ApplicationArguments.In addition, they function exactly the same, even the method name.Declare an ApplicationRunner with the lowest priority:

package cn.felord;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * Lowest priority
 * @author felord.cn
 * @since 13:00
 **/
@Slf4j
@Component
public class DefaultApplicationRunner implements ApplicationRunner, Ordered {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("i am applicationRunner");
        Set<String> optionNames = args.getOptionNames();
        log.info("optionNames = " + optionNames);
        String[] sourceArgs = args.getSourceArgs();
        log.info("sourceArgs = " + Arrays.toString(sourceArgs));
        List<String> nonOptionArgs = args.getNonOptionArgs();
        log.info("nonOptionArgs = " + nonOptionArgs);
        List<String> optionValues = args.getOptionValues("foo");
        log.info("optionValues = " + optionValues);
    }

    @Override
    public int getOrder() {
        return Integer.MIN_VALUE+2;
    }
}

The execution results of three classes are printed in sequence:

2020-06-01 13:02:39.420  INFO 19032 --- [           main] c.f.MybatisResultmapApplication  : Started MybatisResultmapApplication in 1.801 seconds (JVM running for 2.266)
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.HighOrderCommandLineRunner   : i am highOrderRunner
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.LowOrderCommandLineRunner    : i am lowOrderRunner
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : i am applicationRunner
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : optionNames = []
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : sourceArgs = []
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : nonOptionArgs = []
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : optionValues = null

The Ordered interface cannot be replaced by the @Order comment.

4. Pass-through parameters

I believe that many students are beginning to be interested in these two methods.Spring Boot applications can accept parameters when they start, in other words, the main method of Spring Boot can accept parameters.These parameters are passed through the command line java-jarYourapp.jar<param>to pass.The CommandLineRunner receives these interfaces as is, and these parameters can also be encapsulated in the ApplicationArguments object for calls by the ApplicationRunner.Let's take a look at how ApplicationArguments works:

  • getSourceArgs() is passed to the application's original parameters, returning an array of strings for those parameters.

  • getOptionNames() Gets the set of Set strings for the option name.For example--Spring.profiles.active=dev--debug will return ["spring.profiles.active","debug"].

  • getOptionValues(String name) gets the option value corresponding to that name by name.For example, --foo=bar --foo=baz will return ["bar","baz"].

  • containsOption(String name) is used to determine if an option's name is included.

  • getNonOptionArgs() is used to get all the no-option parameters.

    Next let's try a wave where you can run a Spring Boot app, Jar

java -jar yourapp.jar --foo=bar --foo=baz --dev.name=Small Fatty Man java felordcn

Or open the configuration item for Spring Boot to apply the main method in the IDEA development tool and configure it as follows, as with other IDE tools.

Run the Spring Boot application and it will print out:

2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = --foo=bar
2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = --foo=baz
2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = --dev.name=Small Fatty Man
2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = java
2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = felordcn
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : i am highOrderRunner
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.LowOrderCommandLineRunner    : i am lowOrderRunner
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : i am applicationRunner
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : optionNames = [dev.name, foo]
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : sourceArgs = [--foo=bar, --foo=baz, --dev.name=Small Fatty Man, java, felordcn]
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : nonOptionArgs = [java, felordcn]
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : optionValues = [bar, baz]

Then you can execute some logic dynamically according to your actual needs.

5. Summary

Today we have explained CommandLineRunner and ApplicationRunner, from usage to sequential execution, and introduced and demonstrated Spring Boot pass parameters, which we hope will help you.More attention: Small Fatty Man, more programming dry goods to share with you.

Focus on Public Number: Felordcn for more information

Personal blog:https://felord.cn

Tags: Programming Spring Java Lombok Tomcat

Posted on Mon, 01 Jun 2020 22:56:55 -0400 by vjbrantner@purd