SpringBoot的CommandLineRunner和ApplicationRunner原创
1年前
297733
1 ApplicationRunner和CommandLineRunner
- 如果我们想在SpringBoot启动完成之后立即做一些什么业务处理,就可以实现SpringBoot提供的这个俩个接口去完成。注意是启动完成,也就意味着你可以在这个接口里面使用SpringBoot提供的所有功能了。
1.1 ApplicationRunner接口源码
ApplicationRunner这个接口非常简单就一个方法,源码如下:
- ApplicationArguments 应用参数处理类,这个类可以处理以双横线开头的参数:–foo=bar。
1.2 CommandLineRunner接口源码
CommandLineRunner这个接口非常简单就一个方法,源码如下:
2 先把代码跑起来看看
- pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.study.demo</groupId>
<artifactId>spring-boot-runner-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<name>springbootrunner</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<!-- lookup parent from repository -->
<relativePath/>
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- ApplicationRunnerDemo类实现了ApplicationRunner接口
package com.study.demo.runner;
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;
/**
* CommandLineRunner 和 ApplicationRunner这俩个类的执行时机都是一样的,都是在SpringBoot启动的倒数第二步开始执行。
* 倒数第二步基本上等于SpringBoot已经启动完毕了。可以去看SpringApplication.run(Application.class, args);run方法的源码。
*
* CommandLineRunner 和 ApplicationRunner这俩个类谁先执行?
* 同等优先级的情况下ApplicationRunner类先执行。
* 不同等优先级的情况下:看@Order(1)的值,@Order(1)的值越小,越先执行。
*/
//@Order(Ordered.HIGHEST_PRECEDENCE)
@Order(2)
@Component
public class ApplicationRunnerDemo implements ApplicationRunner {
/**
* java -jar spring-boot-runner-demo-1.0-SNAPSHOT.jar --test=show p1 p2 p3
* @param args incoming application arguments
* @throws Exception 业务异常
*/
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner的作用就是,SpringBoot启动成功之后,我就立马做点事情,主要功能就是项目启动成功之后," +
"ApplicationRunner默认比CommandLineRunner优先执行");
System.out.println("ApplicationArguments类的getSourceArgs()方法获取到的是最原始的参数: " +
"你传的是什么参数,这里拿到的就是什么参数:->" + Arrays.toString(args.getSourceArgs()));
System.out.println("ApplicationArguments类的getOptionNames()方法获取到的是参数的key值->: " + args.getOptionNames());
System.out.println("如果传递的参是这样的:--foo=bar --debug,那么getOptionNames()获取到的参数是这样的[\"foo\", \"debug\"]----> " + args.getOptionNames());
System.out.println("ApplicationArguments类的getNonOptionArgs方法获取到的参数都是没用--开头传递的参数->: " + args.getNonOptionArgs());
String key = "test";
if (args.containsOption(key)) {
System.out.println("如果存在--test这个参数,把test参数的值取出来给大家伙看一下:" + args.getOptionValues(key));
}
String noKey = "noKey";
if (!args.containsOption(noKey)) {
System.out.println("兄弟们不存在--noKey这个参数" );
}
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
System.out.println();
}
}
- CommandLineRunnerDemo类实现了CommandLineRunner接口
package com.study.demo.runner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* CommandLineRunner 和 ApplicationRunner这俩个类的执行时机都是一样的,都是在SpringBoot启动的倒数第二步开始执行。
* 倒数第二步基本上等于SpringBoot已经启动完毕了。可以去看SpringApplication.run(Application.class, args);run方法的源码。
*
* CommandLineRunner 和 ApplicationRunner这俩个类谁先执行?
* 同等优先级的情况下ApplicationRunner类先执行。
* 不同等优先级的情况下:看@Order(1)的值,@Order(1)的值越小,越先执行。
*/
//@Order(Ordered.HIGHEST_PRECEDENCE)
@Order(1)
@Component
public class CommandLineRunnerDemo implements CommandLineRunner {
/**
* java -jar .\spring-boot-runner-demo-1.0-SNAPSHOT.jar --test=show p1 p2 p3
* @param args incoming main method arguments
* @throws Exception 业务异常
*/
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner的作用就是,SpringBoot启动成功之后,我就立马做点事情," +
"主要功能就是项目启动成功之后,ApplicationRunner默认比CommandLineRunner优先执行");
System.out.println("CommandLineRunner拿到的是最原始的参数,你传的是什么参数,这里拿到的就是什么参数:" + Arrays.toString(args));
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
System.out.println();
}
}
- SpringBoot启动类
package com.study.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
/**
* 使用 java -jar 命令启动jar包,并给main方法传递参数,参数之间用空格隔开
* java -jar .\spring-boot-runner-demo-1.0-SNAPSHOT.jar --test=show p1 p2 p3
* @param args 参数数组
*/
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2.1 将这个SpringBoot项目打成jar项目运行
- 使用mvn clean package将项目打成jar包
- 使用java -jar spring-boot-runner-demo-1.0-SNAPSHOT.jar --test=show p1 p2 p3 这个命令运行jar包,注意参数之间用空格隔开。
3 讲解代码
3.1 先看这个类ApplicationRunnerDemo
- ApplicationRunnerDemo这个类,我们实现了ApplicationRunner接口,并且在类上面使用了@Order(2)注解。
3.2 再看这个类CommandLineRunnerDemo
- CommandLineRunnerDemo这个类,我们实现了CommandLineRunner接口,并且在类上面使用了@Order(1)注解。
3.3 参数是怎么传递过来的?这俩个接口又会在什么时候执行呢?
- 当我们执行java -jar spring-boot-runner-demo-1.0-SNAPSHOT.jar --test=show p1 p2 p3 这个命令运行jar包这条命令的时候,实际上执行的是SpringBoot启动类的main方法,后面以空格隔开的参数,会传给main方法的参数args,这个是Java的基础功能,不是SpringBoot提供的功能。
- 最关键的地方来了,ApplicationArguments类出现了。注意上图中这行代码,将我们命令行中的参数,通过构造方法传给DefaultApplicationArguments这个类了。
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
- 我们来看DefaultApplicationArguments拿到我们的参数之后做了什么处理吧?
到这里参数传递,参数解析,获取参数都已经讲完了。
- 然后,又将applicationArguments这个对象,传给callRunners(context, applicationArguments)方法了;
ApplicationRunner和CommandLineRunnerDemo的执行时机,也讲完了。
点赞收藏
分类: