springboot2 启动传参_Spring Boot 2 实战:自定义启动运行逻辑实例详解

本文详细介绍了如何在Spring Boot 2中使用CommandLineRunner和ApplicationRunner接口自定义启动时的运行逻辑。通过示例展示了如何设置执行顺序,并解析命令行参数。此外,还探讨了两者之间的区别。
摘要由CSDN通过智能技术生成

本文实例讲述了Spring Boot 2 实战:自定义启动运行逻辑。分享给大家供大家参考,具体如下:

1. 前言

不知道你有没有接到这种需求,项目启动后立马执行一些逻辑。比如缓存预热,或者上线后的广播之类等等。可能现在没有但是将来会有的。想想你可能的操作, 写个接口上线我调一次行吗?NO!NO!NO!这种初级菜鸟才干的事。今天告诉你个骚操作使得你的代码更加优雅,逼格更高。

2. CommandLineRunner 接口

package org.springframework.boot;

import org.springframework.core.Ordered;

import org.springframework.core.annotation.Order;

/**

* Interface used to indicate that a bean should run 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.

*

* 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;

}

CommandLineRunner 作用是当springApplication 启动后,在同一应用上下文中定义的多个 CommandLineRunner 类型的 Spring Bean 按照标记顺序执行。如果你想替代以数组方式接收 args 参数 可以用 另一个接口代替 org.springframework.boot.ApplicationRunner 。

talk is cheap show your code 下面我就来操作一波演示一下。

2.1 优先级比较高的 CommandLineRunner 实现

package cn.felord.begin;

import lombok.extern.slf4j.Slf4j;

import org.springframework.boot.CommandLineRunner;

import org.springframework.core.Ordered;

import org.springframework.stereotype.Component;

/**

* 优先级比较高 通过实现接口{@link Ordered}的方式 来指定优先级

* 命令行测试参数 --foo=bar --dev.name=码农小胖哥 java,springboot

* @author Felordcn

* @since 2019/6/17 23:06

*/

@Slf4j

@Component

public class HighOrderCommandLineRunner implements CommandLineRunner , Ordered {

@Override

public void run(String... args) throws Exception {

log.info("i am highOrderRunner");

}

@Override

public int getOrder() {

return Ordered.HIGHEST_PRECEDENCE;

}

}

2.2 优先级比较低的 CommandLineRunner 实现:

package cn.felord.begin;

import lombok.extern.slf4j.Slf4j;

import org.springframework.boot.CommandLineRunner;

import org.springframework.core.Ordered;

import org.springframework.core.annotation.Order;

import org.springframework.stereotype.Component;

/**

* 优先级比较低 通过注解{@link Order}方式来指定优先级

* 比最优大64 说明会在 {@link HighOrderCommandLineRunner} 之后执行

*

* @author Felord

* @since 2019/6/17 23:07

*/

@Slf4j

@Order(Ordered.HIGHEST_PRECEDENCE + 64)

@Component

public class LowOrderCommandLineRunner implements CommandLineRunner {

@Override

public void run(String... args) throws Exception {

log.info("iamlowOrderRunner");

}

}

2.3 用 ApplicationRunner 实现最低优先级:

package cn.felord.begin;

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 org.springframework.util.CollectionUtils;

import java.util.List;

/**

* 优先级最低的实现

* @author Felordcn

* @since 2019/6/18 22:13

*/

@Slf4j

@Component

public class DefaultApplicationRunner implements ApplicationRunner, Ordered {

@Override

public void run(ApplicationArguments args) throws Exception {

log.info("iamapplicationRunner");

}

@Override

public int getOrder() {

return Ordered.HIGHEST_PRECEDENCE+65;

}

}

启动springboot 后控制台打印出了执行结果:

2019-11-02 21:18:14.603 INFO 10244 --- [ main] c.f.begin.HighOrderCommandLineRunner : i am highOrderRunner

2019-11-02 21:18:14.604 INFO 10244 --- [ main] c.f.begin.LowOrderCommandLineRunner : i am lowOrderRunner

2019-11-02 21:18:14.604 INFO 10244 --- [ main] c.f.begin.DefaultApplicationRunner : i am applicationRunner

3. 进阶操作 —— 读取通过Spring Boot命令行启动注入的参数

达到我们开篇的期望结果。那么这两个接口啥区别呢? Spring 官方不会吃饱了没事干弄两个这来折腾人,应该是有区别的,根据接口方法 run 方法可以看出来参数都不一样,额外科普一下 Spring Boot 如何传递额外参数通过命令行 执行 java -jar 传递给 main 方法,规则如下

键值对 格式为 --K=V 多个使用空格隔开

值 多个空格隔开 在idea 开发工具中打开main方法配置项,进行如下配置,其他ide工具同理。参数内容为:

--foo=bar --dev.name=码农小胖哥 java springboot

HighOrderCommandLineRunner 打印一下 args 参数:

package cn.felord.begin;

import lombok.extern.slf4j.Slf4j;

import org.springframework.boot.CommandLineRunner;

import org.springframework.core.Ordered;

import org.springframework.stereotype.Component;

/**

* 优先级比较高 通过实现接口{@link Ordered}的方式 来指定优先级

* 命令行测试参数 --foo=bar --dev.name=码农小胖哥 java,springboot

* @author dax

* @since 2019/6/17 23:06

*/

@Slf4j

@Component

public class HighOrderCommandLineRunner implements CommandLineRunner , Ordered {

@Override

public void run(String... args) throws Exception {

for (String arg : args) {

System.out.println("arg = " + arg);

}

log.info("i am highOrderRunner");

}

@Override

public int getOrder() {

return Ordered.HIGHEST_PRECEDENCE;

}

}

然后 DefaultApplicationRunner 的 ApplicationArguments 我们也一探究竟:

package cn.felord.begin;

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 org.springframework.util.CollectionUtils;

import java.util.List;

/**

* @author Felord

* @since 2019/6/18 22:13

*/

@Slf4j

@Component

public class DefaultApplicationRunner implements ApplicationRunner, Ordered {

@Override

public void run(ApplicationArguments args) throws Exception {

log.info("i am applicationRunner");

args.getOptionNames().forEach(System.out::println);

System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>");

String[] sourceArgs = args.getSourceArgs();

if (sourceArgs!=null){

for (String sourceArg : sourceArgs) {

System.out.println("sourceArg = " + sourceArg);

}

}

System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

List foo = args.getOptionValues("foo");

if (!CollectionUtils.isEmpty(foo)){

foo.forEach(System.out::println);

}

System.out.println("++++++++++++");

List nonOptionArgs = args.getNonOptionArgs();

System.out.println("nonOptionArgs.size() = " + nonOptionArgs.size());

nonOptionArgs.forEach(System.out::println);

}

@Override

public int getOrder() {

return Ordered.HIGHEST_PRECEDENCE+65;

}

}

重新启动 Spring Boot 控制台打印出了结果:

arg = --foo=bar

arg = --dev.name=码农小胖哥

arg = java

arg = springboot

2019-11-02 21:18:14.603 INFO 10244 --- [ main] c.f.begin.HighOrderCommandLineRunner : i am highOrderRunner

2019-11-02 21:18:14.604 INFO 10244 --- [ main] c.f.begin.LowOrderCommandLineRunner : i am lowOrderRunner

2019-11-02 21:18:14.604 INFO 10244 --- [ main] c.f.begin.DefaultApplicationRunner : i am applicationRunner

dev.name

foo

>>>>>>>>>>>>>>>>>>>>>>>>>>

sourceArg = --foo=bar

sourceArg = --dev.name=码农小胖哥

sourceArg = java

sourceArg = springboot

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

bar

++++++++++++

nonOptionArgs.size() = 2

java

springboot

我们发现可以利用这两个接口来读取 Spring Boot 命令行参数。其实我们还可以使用 @Value 注解来读取,这里不进行讲解,有兴趣可以自己尝试。到这里 ApplicationRunner 与 CommandLineRunner 的区别从控制台我们就很了然了。

4. ApplicationRunner 与 CommandLineRunner 的区别

从上面的 log 我们知道 arg= 为 CommandLineRunner 的 args数组打印,仅仅单纯把上面的参数以空格为规则解析成了原汁原味的数组。而 ApplicationRunner 则更加精细化。通过打印可以知道 ApplicationArguments 提供了一些很有用的参数解析方法:

args.getOptionNames() 是获取键值对 --K=V 中的 K

args.getOptionValues("foo") 用来通过 K 来获取键值对的值 V

args.getSourceArgs() 等同于 CommandLineRunner 的 args 数组

args.getNonOptionArgs() 最惨用来获取单身狗

要注意的是 解析 ApplicationArguments 时要处理空指针问题。

5. 总结

今天我们通过对 CommandLineRunner 和 ApplicationRunner 讲解。解决了如何在 Spring Boot 启动时执行一些逻辑的问题以及如何来编排多个启动逻辑的优先级顺序。同时我们进阶一步,通过这两个方法读取 Spring Boot 启动项参数。进而也搞清楚了这两个接口之间的细微的区别。

希望本文所述对大家java程序设计有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值