Overview
There may be scenarios in development where you need to execute something when the container starts. For example, reading configuration files, database connections, etc. SpringBoot provides us with two interfaces to help us achieve this requirement. The two startup loading interfaces are: CommandLineRunner and ApplicationRunner. Spring provides the interface InitializingBean, and jdk provides @PostConstruct
The difference between CommandLineRunner and ApplicationRunner
The functions of CommandLineRunner and ApplicationRunner are the same. The difference is that the run() method of the CommandLineRunner interface receives a String array as a parameter, which is the most original parameter, without any processing; while the run() method of the ApplicationRunner interface receives an ApplicationArguments object as a parameter, which further refines the original parameters. of packaging.
When the program starts, the parameters we pass to the main() method can be accessed by the run() method of the class that implements the CommandLineRunner and ApplicationRunner interfaces, which can receive the parameters passed when starting the service. We can create multiple classes that implement the CommandLineRunner and ApplicationRunner interfaces. In order to make them execute in a certain order, you can use the @Order annotation or implement the Ordered interface.
Example of ApplicationRunner interface
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; @Component @Order(value = 1) public class JDDRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println("This is to test the ApplicationRunner interface"); String strArgs = Arrays.stream(arg0.getSourceArgs()).collect(Collectors.joining("|")); System.out.println("Application started with arguments:" + strArgs); } }
Specify parameters when starting: java -jar xxxx.jar data1 data2 data3
This is to test the ApplicationRunner interface
Application started with arguments:data1|data2|data3
CommandLineRunner interface example
import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; @Component public class TestCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("This is to test the CommandLineRunn interface"); String strArgs = Arrays.stream(args).collect(Collectors.joining("|")); System.out.println("Application started with arguments:" + strArgs); } }
Specify parameters when starting: java -jar xxxx.jar data1 data2 data3
operation result:
This is to test the CommandLineRunn interface
Application started with arguments:data1|data2|data3
Execution order of CommandLineRunner and ApplicationRunner
In the spring boot program, we can use more than one bean that implements CommandLineRunner and ApplicationRunner. In order to execute the run() method of these beans in order, you can use the @Order annotation or the Ordered interface.
@Component @Order(2) public class ApplicationRunnerBean1 implements ApplicationRunner { @Override public void run(ApplicationArguments arg0) throws Exception { System.out.println("ApplicationRunnerBean 1"); } } @Component @Order(4) public class ApplicationRunnerBean2 implements ApplicationRunner { @Override public void run(ApplicationArguments arg0) throws Exception { System.out.println("ApplicationRunnerBean 2"); } } @Component @Order(1) public class CommandLineRunnerBean1 implements CommandLineRunner { @Override public void run(String... args) { System.out.println("CommandLineRunnerBean 1"); } } @Component @Order(3) public class CommandLineRunnerBean2 implements CommandLineRunner { @Override public void run(String... args) { System.out.println("CommandLineRunnerBean 2"); } }
Results of the:
CommandLineRunnerBean 1 ApplicationRunnerBean 1 CommandLineRunnerBean 2 ApplicationRunnerBean 2
Some interfaces are not executed when implementing multiple ApplicationRunner
@Component @Slf4j public class RunnerTest1 implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { while (true) { System.out.println("this is RunnerTest1"); Thread.sleep(100); } } } @Component @Slf4j public class RunnerTest2 implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { while (true) { System.out.println("this is RunnerTest2"); Thread.sleep(100); } } }
Only the methods in RunnerTest1 will be executed.
By analyzing the source code of springboot startup, we can find that after the applicationContext container is loaded, the callRunners method of the SpringApplication class will be called:
This method will obtain all interface beans that implement ApplicationRunner and CommandLineRunner, and then execute the corresponding run methods in sequence, and execute them in the same thread. Therefore, if the run method of a bean that implements the ApplicationRunner interface keeps looping without returning, subsequent code will not be executed.
ApplicationRunner, InitializingBean, @PostConstruct execution order issues
Usage of InitializingBean interface
The InitializingBean interface provides an initialization method for beans. It only includes the afterPropertiesSet method. All classes that inherit this interface will execute this method when initializing the bean. Note that it is best to add Spring annotation injection to implement this interface, such as @Component
Usage of @PostConstruct annotation
If you want to complete certain initialization operations when generating an object, but these initialization operations rely on dependency injection, then you cannot implement it in the constructor. For this purpose, you can use @PostConstruct to annotate a method to complete initialization. The method annotated with @PostConstruct will be automatically called after dependency injection is completed. Priority: Constructor >> @Autowired >> @PostConstruct
@Component public class Test implements InitializingBean, ApplicationRunner, CommandLineRunner { @PostConstruct public void init(){ System.out.println("PostConstruct method execution"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("InitializingBean method execution"); } @Override public void run(ApplicationArguments args) throws Exception { System.out.println("This is to test the ApplicationRunner interface"); } @Override public void run(String... args) throws Exception { System.out.println("This is to test the CommandLineRunn interface"); } }
PostConstruct method execution InitializingBean method execution
This is to test the ApplicationRunner interface. This is to test the CommandLineRunn interface.
It can be seen from this: @PostConstruct>InitializingBean>ApplicationRunner>CommandLineRunner