在使用Spring Boot开发的工作中,我们经常会需要遇到一种功能需求,比如在服务启动时候,去加载一些配置,去请求一下其他服务的接口。Spring Boot给我们提供了三种常用的实现方法:
第一种是实现CommandLineRunner接口,
第二种是实现ApplicationRunner接口
第三种是使用注解:@PostConstruct

1、CommandLineRunner

1、CommandLineRunner执行的时间节点是在Application完成初始化工作之后。
2、CommandLineRunner在有多个实现的时候,可以使用@order注解指定执行先后顺序。
3、源码在:org.springframework.boot.SpringApplication#run(),可以看看

我们先看一下CommandLineRunner的源码:

package org.springframework.boot;

@FunctionalInterface
public interface CommandLineRunner {
void run(String... args) throws Exception;
}

SpringApplication源码:

public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass); try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
} listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, listeners);
throw new IllegalStateException(var10);
} try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}

callRunners方法源码:

private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
Iterator var4 = (new LinkedHashSet(runners)).iterator(); while(var4.hasNext()) {
Object runner = var4.next();
if (runner instanceof ApplicationRunner) {
this.callRunner((ApplicationRunner)runner, args);
} if (runner instanceof CommandLineRunner) {
this.callRunner((CommandLineRunner)runner, args);
}
} }

我们写一个例子实现:


import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component; import java.util.Arrays; @Component
@Order(1)
public class CommandLineRunnerTest implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("----CommandLineRunnerTest1 start---"+ Arrays.toString(args));
}
}

2、ApplicationRunner

ApplicationRunner跟CommandLineRunner是区别是在run方法里接收的参数不同,CommandLineRuner接收的参数是String... args,而ApplicationRunner的run方法的参数是ApplicationArguments

看看ApplicationRunner的源码:

package org.springframework.boot;

@FunctionalInterface
public interface ApplicationRunner {
void run(ApplicationArguments args) throws Exception;
}

我们写一个例子实现:


import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component; import java.util.List;
import java.util.Set; @Component
@Order(1)
public class ApplicationRunnerTest implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("---ApplicationRunnerTest start----"); List<String> nonOptionArgs = args.getNonOptionArgs();
System.out.println("[非选项参数]>>> " + nonOptionArgs);
Set<String> optionNames = args.getOptionNames();
for(String optionName: optionNames) {
System.out.println("[选项参数]>>> name:" + optionName
+ ";value:" + args.getOptionValues(optionName));
}
}
}

3、@PostConstruct

@PostConstruct是在javaEE5的时候引入的,它并不是Spring提供的,但是Spring有对@PostConstruct的实现。并且是在对象加载完之后执行。

先看注解源码

@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}

我们写一个例子实现:

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class PostConstructTest { @PostConstruct
public void start(){
System.out.println("---PostConstruct start---");
} }

运行代码输出结果 :

5、源码

https://gitee.com/Qinux/command-line-runner-demo.git

微信公众号:一凡码农
欢迎交流

Spring Boot自动运行之 CommandLineRunner、ApplicationRunner和@PostConstruct的更多相关文章

  1. Spring Boot自动配置与Spring 条件化配置

    SpringBoot自动配置 SpringBoot的自动配置是一个运行时(应用程序启动时)的过程,简化开发时间,无需浪费时间讨论具体的Spring配置,只需考虑如何利用SpringBoot的自动配置即 ...

  2. Spring Boot自动配置原理、实战

    Spring Boot自动配置原理 Spring Boot的自动配置注解是@EnableAutoConfiguration, 从上面的@Import的类可以找到下面自动加载自动配置的映射. org.s ...

  3. Spring Boot自动配置

    Spring Boot自动配置原理 Spring Boot的自动配置注解是@EnableAutoConfiguration, 从上面的@Import的类可以找到下面自动加载自动配置的映射. org.s ...

  4. Spring boot 自动配置自定义配置文件

    示例如下: 1.   新建 Maven 项目 properties 2.   pom.xml <project xmlns="http://maven.apache.org/POM/4 ...

  5. Spring Boot 自动装配(二)

    目录 目录 前言 1.起源 2.Spring Boot 自动装配实现 2.1.@EnableAutoConfiguration 实现 2.1.1. 获取默认包扫描路径 2.1.2.获取自动装配的组件 ...

  6. Spring Boot自动配置原理(转)

    第3章 Spring Boot自动配置原理 3.1 SpringBoot的核心组件模块 首先,我们来简单统计一下SpringBoot核心工程的源码java文件数量: 我们cd到spring-boot- ...

  7. Spring Boot自动配置如何工作

    通过使用Mongo和MySQL DB实现的示例,深入了解Spring Boot的@Conditional注释世界. 在我以前的文章“为什么选择Spring Boot?”中,我们讨论了如何创建Sprin ...

  8. Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了自定义 Starter 组件

    本章内容 自定义属性快速入门 外化配置 自动配置 自定义创建 Starter 组件 摘录:读书是读完这些文字还要好好用心去想想,写书也一样,做任何事也一样 图 2 第二章目录结构图 第 2 章 Spr ...

  9. Spring Boot 自动配置之@Conditional的使用

    Spring Boot自动配置的"魔法"是如何实现的? 转自-https://sylvanassun.github.io/2018/01/08/2018-01-08-spring_ ...

  10. 将Spring Boot项目运行在Docker上

    将Spring Boot项目运行在Docker上 一.使用Dockerfile构建Docker镜像 1.1Dockerfile常用指令 1.1.1ADD复制文件 1.1.2ARG设置构建参数 1.1. ...

随机推荐

  1. 洛谷P3046 海底高铁 巧用差分统计经过区间次数

    洛谷P3046 海底高铁 -差分统计经过区间次数 题目贴在这里P3406 海底高铁 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 分析 本题题干很长,但是题意理解很简单.就是给定n ...

  2. Linux用户被锁定后如何解锁

    客户的一台机器,按照提供的常用密码尝试使用oracle用户登陆,超过指定次数账号被锁定,提示如下: Account locked due to 6 failed logins 这需要使用root用户解 ...

  3. 20.2 显示的链接到导出符号--《Windows核心编程》

    FAPPROC GetProcAddress(HMOUDLE hInstDll,PCSTR pszSymbolName); 1.根据名称 FARPROC FunctionAddress = (ULON ...

  4. Mac上SnailSvn checkout报错

  5. Java-将文本(字符串)转化成二进制字符

    今天在测试MySQL的Blob相关类型时,这种一般存放的是二进制文本,所以就想插入二进制文本. package com.aaa.dao; public class aaa { public stati ...

  6. RedHat Enterprise Linux 8.0终端命令界面字体放大缩小

    一.打开RedHat的终端命令界面. 二.放大界面中字体,Ctrl + Shit  + "+" 三.缩小界面中字体,Ctrl +  "-"

  7. CF1907

    A 模拟. B 模拟. C 若原字符串中出现次数最多的次数为 \(cnt\),答案是 \(\max(n\%2,cnt\times 2-n)\). D 二分 \(k\),然后从后往前倒,计算出到达每个线 ...

  8. 【LGR-153-Div.2】梦熊联盟 8 月月赛 Ⅳ & Cfz Round 1 & 飞熊杯 #1

    [LGR-153-Div.2]梦熊联盟 8 月月赛 Ⅳ & Cfz Round 1 & 飞熊杯 #1 \(T1\) luogu P9577 「Cfz Round 1」Dead Cell ...

  9. 二进制安装Kubernetes(k8s) v1.27.1 IPv4/IPv6双栈 可脱离互联网

    二进制安装Kubernetes(k8s) v1.27.1 IPv4/IPv6双栈 可脱离互联网 https://github.com/cby-chen/Kubernetes 开源不易,帮忙点个star ...

  10. C++ 多线程的错误和如何避免(2)

    试图 join 一个已经 detach 的线程 如果你已经在某个地方分离了线程,那你不可以在主线程再次 join,这是一个明显的错误 比如: #include <iostream> #in ...