在使用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. 201871010111-刘佳华 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

    实验三 软件工程结对项目 ========== 时间:2021-4-1 项目 内容 课程班级博客链接 课程链接 这个作业要求链接 作业要求 我的课程学习目标 1.了解软件工程过程中结对项目的开发流程 ...

  2. GJK算法:两个凸集的碰撞测试

      GJK算法用于判断两个凸集是否相交,其中GJK是三个提出者的姓名首字母.为了便于理解(偷懒),下面的内容都只在二维平面内讨论. 1. 回顾凸集   可能有很多小伙伴忘了什么是凸集.凸集有很多等价的 ...

  3. Java - CodeForces - 469C

    题目: 现在有一个容器,里面有n个物品,编号为1-n,现在小q可以进行一些操作,每次取出任意两个数,可以把这两个数的编号相加,相减,相乘,再把结果放回容器.问最后小q能否在n-1次操作后使得容器里的唯 ...

  4. 多线程系列(二) -Thread类使用详解

    一.简介 在之前的文章中,我们简单的介绍了线程诞生的意义和基本概念,采用多线程的编程方式,能充分利用 CPU 资源,显著的提升程序的执行效率. 其中java.lang.Thread是 Java 实现多 ...

  5. NC20573 [SDOI2011]染色

    题目链接 题目 题目描述 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如 ...

  6. Centos8 安装 Redis6.0.16

    下载,解压,编译,安装 安装至 /opt/redis/redis-6.0.16 目录 tar xvf redis-6.0.16.tar.gz gcc --version cd redis-6.0.16 ...

  7. windows网络流量监控

    NPCap 官网 https://nmap.org/npcap/ 这是抓包必须先安装的工具,具体的原因可以看 https://github.com/buger/goreplay/wiki/Runnin ...

  8. Goland 使用[临时]

    环境变量 因为module模式的引入, 多个项目可以共用同一套External Libraries, 在File->Settings->Go中, 设置GOROOT为go安装目录, 例如 / ...

  9. VueRouter导航守卫

    VueRouter导航守卫 vue-router提供的导航守卫主要用来通过跳转或取消的方式守卫导航,简单来说导航守卫就是路由跳转过程中的一些钩子函数,路由跳转是一个大的过程,这个大的过程分为跳转前中后 ...

  10. TerminateJobObject是使用

    注意: AssignProcessToJobObject仅适用于win32 desktop app, 比如notepad是适用的,calculator是不适用的 下面的demo是将notepad的句柄 ...