springboot 项目容器启动后如何自动执行指定方法

目录
  • springboot 项目容器启动后自动执行指定
  • springboot 容器及启动过程
    • 问题1:为什么要启动父子两个容器?
    • 问题2:在什么时候启动父容器?
    • 问题3:父容器和子容器的区别?
    • 问题4:怎么保证父容器启动过程中
    • 问题5:容器实际通过什么来管理bean

springboot 项目容器启动后自动执行指定

我们需要写一个class去让它实现ApplicationRunner,然后重写它的run方法就行了,注意类加上@Component注解

注意:这个class需要写在和Application启动类的同级目录或者子级目录下,否则不生效。

代码:

package com.qq.weixin;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

/**
 * @author XuYangWei
 * @Date 2021/1/22 8:56
 */
@Slf4j
@Component
public class TestRuner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {
        log.info("我是Spring容器启动后立即执行的方法,当前时间:"+ DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));
    }
}

springboot 容器及启动过程

SpringBoot会启动两个容器,即父子容器

  • 父容器(Spring容器):AnnotationConfigWebApplicationContex
  • 子容器(SpringMVC容器):AnnotationConfigEmbeddedWebApplicationContex

思考几个问题:

问题1:为什么要启动父子两个容器?

在Spring整体框架的核心概念中,容器是核心思想,而在一个项目中,容器不一定只有一个,Spring中可以包括多个容器,使用上下层关系来管理容器可以解决公共属性抽取的问题,即将公共的属性放到父容器中,对其各个子容器均可见,实现了复用功能,注意子容器对父容器是不可见的。

问题2:在什么时候启动父容器?

准备环境变量,即执行prepareEnvironment方法时,发布ApplicationEnvironmentPreparedEvent事件,BootstrapApplicationListener监听器收到该事件,会初始化父容器

问题3:父容器和子容器的区别?

1.子容器中会创建植入的tomcat容器类,用来管理tomcat服务,父容器没有

2.父容器管理的bean集合是spring框架内置的一些bean,子容器管理的bean集合是我们业务定义的bean以及spring框架内置的bean

问题4:怎么保证父容器启动过程中

执行prepareEnvironment方法时,BootstrapApplicationListener监听器不再重复执行?

父容器初始化完成后,会在webEnvironment属性中加入bootstrap属性标识,这样就可以根据该标识来判断是否需要执行了

问题5:容器实际通过什么来管理bean

容器通过beanFactory来管理对象,父子容器都会各持有一个DefaultListableBeanFactory,即父子容器都会管理各自的bean。

子容器启动流程:

1.执行初始化:初始化webEnvironment以及listeners

2.发布容器启动事件

3.在执行prepareEnvironment步骤时,发布ApplicationEnvironmentPreparedEvent事件,BootstrapApplicationListener监听器收到该事件,会再次调用SpringApplication

  • 初始化和run方法(初始化父容器的步骤类似子容器)

4.创建context,通过判断webEnvironment标识,这时为true,创建AnnotationConfigEmbeddedWebApplicationContext实例

5.执行refreshContext,比较核心的方法,详细说一下:

  • 获取bean工厂,即创建DefaultListableBeanFactory实例
  • 为bean工厂赋一些基础属性,主要有类加载器
  • 为bean工厂注册WebApplicationContextServletContextAwareProcessor,一个BeanPostProcessor,主要用于获取ServletContext
  • 执行beanFactoryPostProcessor,递归处理,主要用于扫描@CompontScan、@Import、@ImportSource等注解的类,首先注册bean元数据到工厂,然后可以修改bean工厂
  • 实例化BeanPostProcessor类并注册到bean工厂单例列表中
  • 实例化消息通知类并注册到bean工厂单例列表中
  • 调用onRefresh方法,初始化一个植入的tomcat容器
  • 注册监听器到消息通知器中,区分为两类:一、从系统配置中加载的监听器(已实例化) 二、已注册但还未实例化的监听器
  • 实例化注册表中的所有bean,创建bean的过程中会执行bean的初始化操作,会执行BeanPostProcessor、afterPropertiesSet、初始化方法等等
  • 调用finishRefresh,启动所有bean,发布ContextRefreshed事件

6.执行afterRefresh,调用实现了ApplicationRunner/CommandLineRunner接口的bean run方法

7.发布ApplicationReadyEvent事件

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 详解Spring Boot 项目启动时执行特定方法

    Springboot给我们提供了两种"开机启动"某些方法的方式:ApplicationRunner和CommandLineRunner. 这两种方法提供的目的是为了满足,在项目启动的时候立刻执行某些方法.我们可以通过实现ApplicationRunner和CommandLineRunner,来实现,他们都是在SpringApplication 执行之后开始执行的. CommandLineRunner接口可以用来接收字符串数组的命令行参数,ApplicationRunner 是使用App

  • 详解spring boot容器加载完后执行特定操作

    有时候我们需要在spring boot容器启动并加载完后,开一些线程或者一些程序来干某些事情.这时候我们需要配置ContextRefreshedEvent事件来实现我们要做的事情 1.ApplicationStartup类 public class ApplicationStartup implements ApplicationListener<ContextRefreshedEvent>{ public void onApplicationEvent(ContextRefreshedEve

  • Spring Boot 项目启动自动执行方法的两种实现方式

    目录 实际应用场景: 第一种实现ApplicationRunner接口 第二种实现CommandLineRunner接口 对比: 注意: 实际应用场景: springboot项目启动成功后执行一段代码,如系统常量,配置.代码集等等初始化操作:执行多个方法时,执行顺序使用Order注解或Order接口来控制. Springboot给我们提供了两种方式 第一种实现ApplicationRunner接口 package org.mundo.demo.core; import org.springfra

  • springBoot启动时让方法自动执行的几种实现方式

    在springBoot中我们有时候需要让项目在启动时提前加载相应的数据或者执行某个方法,那么实现提前加载的方式有哪些呢?接下来我带领大家逐个解答 1.实现ServletContextAware接口并重写其setServletContext方法 @Component public class TestStarted implements ServletContextAware { /** * 在填充普通bean属性之后但在初始化之前调用 * 类似于initializingbean的afterpro

  • springboot 项目容器启动后如何自动执行指定方法

    目录 springboot 项目容器启动后自动执行指定 springboot 容器及启动过程 问题1:为什么要启动父子两个容器? 问题2:在什么时候启动父容器? 问题3:父容器和子容器的区别? 问题4:怎么保证父容器启动过程中 问题5:容器实际通过什么来管理bean springboot 项目容器启动后自动执行指定 我们需要写一个class去让它实现ApplicationRunner,然后重写它的run方法就行了,注意类加上@Component注解 注意:这个class需要写在和Applicat

  • SpringBoot项目修改访问端口和访问路径的方法

    创建SpringBoot项目,启动后,默认的访问路径即主机IP+默认端口号8080:http://localhost:8080/ 此时,我们就可以访问Controller层的接口了,如:http://localhost:8080/hello package com.springboot.test; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.a

  • Springboot启动后立即某个执行方法的四种方式

    目录 注解@PostConstruct CommandLineRunner接口 实现ApplicationRunner接口 实现ApplicationListener 四种方式的执行顺序 总结 最新需要在项目启动后立即执行某个方法,然后特此记录下找到的四种方式 注解@PostConstruct 使用注解@PostConstruct是最常见的一种方式,存在的问题是如果执行的方法耗时过长,会导致项目在方法执行期间无法提供服务. @Component public class StartInit {

  • springboot项目突然启动缓慢的解决

    目录 springboot项目突然启动缓慢 springboot启动太慢优化 1.组件自动扫描带来的问题(@SpringBootApplication) 2.如何避免组件自动扫描带来的问题(不使用@ SpringBootApplication) 3.引发的问题--无法扫描组件 4.千古红楼只一梦,竹篮打水一场空 5.debug debug,bug bug更健康 6.分析Positive matches和Negative matches 7.再次优化配置信息 8.小结一下 springboot项目

  • java如何实现项目启动时执行指定方法

    本文实例为大家分享了java项目启动时执行指定方法,供大家参考,具体内容如下 想到的就是监听步骤如下: 1.配置web.xml <listener> <listener-class>com.listener.InitListener</listener-class> </listener> 2.编写InitListener类 package com.listener; import java.io.File; import javax.servlet.Ser

  • 页面加载完后自动执行一个方法的js代码

    1.在body中用onload: <body onload="myfunction()"> 2.在脚本中用window.onload: <script type="text/javascript"> function myfun() { alert("this window.onload"); } /*用window.onload调用myfun()*/ window.onload=myfun;//不要括号 </scr

  • docker容器启动后添加端口映射

    概要 网上有许多人在查找关于容器启动后能否进行端口映射的问题.我曾经也问过度娘,很遗憾我没找到.本文就这个问题给出一个解决方法,旨在抛砖引玉.本文的思路是使用iptables的端口转发,这也是docker端口映射内部的实现机制,只不过我是显示地写出来罢了,为的就是让查找这个问题的人对docker的端口映射有一个直观的了解. 结论:容器启动后是可以添加端口映射的,但不建议手工添加,最好使用docker提供的功能. 步骤 创建两个容器并进行了端口映射,结果如图所示: 假如,我start一个容器,其内

  • SpringBoot项目中遇到的BUG问题及解决方法

    1.启动项目的时候报错 1.Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled. 解决方法: 在yml配置文件中加入debug: true,因为默认的话是false 2.在集成mybatis时mapper包中的类没被扫描 org.springframework.beans.factory.NoSuchBean

  • Docker容器启动时初始化Mysql数据库的方法

    1. 前言 Docker在开发中使用的越来越多了,最近搞了一个Spring Boot应用,为了方便部署将Mysql也放在Docker中运行.那么怎么初始化 SQL脚本以及数据呢? 我这里有两个传统方案. 第一种方案是在容器启动后手动导入,太low了不行.第二种在Spring Boot客户端连接Mysql容器时初始化数据库,你可以参考使用flyway进行数据库版本控制一文,但是这依赖客户端的能力.能不能做到Mysql容器启动时就自己初始化数据库呢?当然可以!今天就来演示一下.全部代码见文末. 2.

  • 在vue项目创建的后初始化首次使用stylus安装方法分享

    项目创建报错: This dependency was not found: * !!vue-style-loader!css-loader?{"minimize":false,"sourceMap":false}!../../node_modules/vue-loader/lib/style-compiler/index?{"vue":true,"id":"data-v-1d57e5ea","s

随机推荐