Spring Boot:CommandLineRunner 和 ApplicationRunner 区别

My GitHub Home Page

区别

先看下两者的签名:

CommandLineRunner

package org.springframework.boot;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 * Interface used to indicate that a bean should <em>run</em> when it is contained within
 * a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined
 * within the same application context and can be ordered using the {@link Ordered}
 * interface or {@link Order @Order} annotation.
 * <p>
 * If you need access to {@link ApplicationArguments} instead of the raw String array
 * consider using {@link ApplicationRunner}.
 *
 * @author Dave Syer
 * @see ApplicationRunner
 */
@FunctionalInterface
public interface CommandLineRunner {

    /**
     * Callback used to run the bean.
     * @param args incoming main method arguments
     * @throws Exception on error
     */
    void run(String... args) throws Exception;

}

ApplicationRunner

package org.springframework.boot;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 * Interface used to indicate that a bean should <em>run</em> when it is contained within
 * a {@link SpringApplication}. Multiple {@link ApplicationRunner} beans can be defined
 * within the same application context and can be ordered using the {@link Ordered}
 * interface or {@link Order @Order} annotation.
 *
 * @author Phillip Webb
 * @since 1.3.0
 * @see CommandLineRunner
 */
@FunctionalInterface
public interface ApplicationRunner {

    /**
     * Callback used to run the bean.
     * @param args incoming application arguments
     * @throws Exception on error
     */
    void run(ApplicationArguments args) throws Exception;

}

不难看出,两者都是接口,且存在于同一个包下,功能均为执行Spring Boot项目启动时的初始化。

唯一的区别就是参数类型不同,前者为String… args,后者封装为ApplicationArguments args。

用法示例

定义项目及其依赖

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.lewis.github</groupId>
    <artifactId>blog-demo</artifactId>
    <version>1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

项目基于 Spring Boot

src/main/java/hello/Application.java

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

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

}

CommandLineRunner 示例

src/main/java/hello/FirstAppRunner.java

package hello;

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

import java.util.Arrays;

@Order(value = 1)
@Component
public class FirstAppRunner implements CommandLineRunner {

    private static final Logger logger = LoggerFactory.getLogger(FirstAppRunner.class);

    @Override
    public void run(String... args) throws Exception {
        logger.info("CommandLineRunner:{}", Arrays.asList(args));
    }

}

执行:

  • mvn clean package
  • java -jar target/blog-demo-1.0.jar hello world

输出:

  • CommandLineRunner:[hello, world]

ApplicationRunner 示例

src/main/java/hello/SecondAppRunner.java

package hello;

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

import java.util.Arrays;

@Order(value = 2)
@Component
public class SecondAppRunner implements ApplicationRunner {

    private static final Logger logger = LoggerFactory.getLogger(SecondAppRunner.class);

    @Override
    public void run(ApplicationArguments args) throws Exception {
        logger.info("ApplicationRunner:{}", Arrays.asList(args.getSourceArgs()));
        logger.info("OptionNames:{}", args.getOptionNames());
    }

}

再次执行:

  • mvn clean package
  • java -jar target/blog-demo-1.0.jar --name=lewis --role=coding

输出:

  • CommandLineRunner:[--name=lewis, --role=coding]
  • ApplicationRunner:[--name=lewis, --role=coding]
  • OptionNames:[role, name]