初识SpringApplication原理 (来自Spring Boot 2.0深度实践之核心技术篇的学习)

初识SpringApplication运行原理

  • 准备阶段

    

  1. 配置Spring Bean的来源

     

     默认我们配置的路径就是classpath:

  1. 推断:web类型

     

     Web类型推断的实现:

     ①判断webApplicationType 是web Flux类型并且不是Servlet类型,则返回web Flux类型。否则进行下一步。

     ②判断webApplicationType  如果是no web类型,返回NONE。否则 返回Servlet类型 。

       注意:如果我们的web flux 与 Servlet都配置了,那么Spring会判定该web类型是Servlet。 当然我们的Web类型的Spring也  可  以通过Application.WebApplicationType = WebApplicationType.NONE设置为no web 类型。

  1. 加载:应用上下文初始化

     

      应用上下文初始化其实就是一些关于ApplicationContext的初始化参数,需要在启动之前进行加载,因此以这种方式进行加      载。

     加载方式:

    ①实现类:SpringFactoriesLoader

    ②配置资源:META-INF  -->  spring.factories

    ③排序:@Order()或者实现Order接口(一般的注解都能使用接口实现方式来替代)

   自定义ApplicationContextInitializer

   ①实现类:

@Order(Ordered.HIGHEST_PRECEDENCE)
public class HelloWorldApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext context) {
        System.out.println("HelloWorldApplicationContextInitializer :" +context.getId() );
    }
}

@Order(Ordered.LOWEST_PRECEDENCE)
public class AfterHelloWorldApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext context) {
        System.out.println("AfterHelloWorldApplicationContextInitializer :" + context.getId());
    }
}

  ②配置资源

  

 

  运行结果:

  

  细心的能看出来,我们实现接口的时候上面有我们的排序注解,排序的顺序就是我们控制台上打印出来的顺序。

 

  1. 加载:应用监听器

     

     监听器的加载机制和我们ApplicationContextInitializer的加载机制是一样,只不过实现的接口不一样而已。

    自定义监听器:

   ①实现我们的ApplicationListener并且注解排序

@Order(Ordered.HIGHEST_PRECEDENCE)
public class FirstHelloWorldApplicationListener implements ApplicationListener<ApplicationContextEvent> {
    @Override
    public void onApplicationEvent(ApplicationContextEvent context) {
        System.out.println("FirstHelloWorldApplicationListener.id = " + context.getApplicationContext().getId());
    }
}

 配置资源

@Order(Ordered.LOWEST_PRECEDENCE)
public class AfterHelloWorldApplicationListener implements ApplicationListener<ApplicationContextEvent> {
    @Override
    public void onApplicationEvent(ApplicationContextEvent context) {
        System.out.println("AfterHelloWorldApplicationListener.id = " + context.getApplicationContext().getId());
    }
}

  运行结果:

  

  1. 推断:main的主类

    

    通过异常堆栈的方式将我们拥有main方法的堆栈元素找到,再获取该堆栈的ClassName,则此类为主类。

  • 运行阶段

    

    

从源码可以看出基本上可以分为以下几个步骤:

  1. 加载:SpringApplication运行监听器  getRunListeners(args)

加载出SpringApplicationRunListeners类,该类控制我们监听器的生命周期。

     2.运行:SpringApplication运行监听器  starting(listeners)

    

    将我们的SpringApplicationRunListener的实现类都一一启动。

    3.监听:Spring Boot事件、Spring事件

    

    该类启动之后,会将我们Spring中的Listener都启动,开始监听模式:

     

  1. 创建:应用上下文、Environment、其他(不是很重要)
  2. 失败:故障分析报表

    

    看名称就知道每一步是做什么的。里面有应用上下文、Environment、故障分析报表、其他(不是很重要)。

    注意:细心的同学可以看出,我们的prepareContext()方法是用来加载配置资源的。

  1. 回调:CommandLineRunner、ApplicationRunner

      

      最后进行我们的回调

     

     CommandLineRunner、ApplicationRunner用来对我们Bean的排序工作,比如我们监听器的排序工作。

   自定义实现ApplicationContextRunListener

  ①实现我们SpringApplicationRunListener 接口,此处没有进行排序。

public class FirstHelloWorldRunListener implements SpringApplicationRunListener {
    public FirstHelloWorldRunListener(SpringApplication application, String[] args) {
    }

//这一步必须有,否则报错

    @Override
    public void starting() {
        System.out.println("FirstHelloWorldRunListener 已经开启!");
    }

    ...其他重写忽略
}

 ②配置资源

  

  运行结果:

  

可以看出RunListener监听器比我们banner还要早,那是因为run方法中,starting比banner早一步。

 

上篇文章遗留问题:

ApplicationContext什么时候加载我们@Configuration?

我们每一个启动类中都有@SpringBootApplication注解,注解里面扫描了它下面所有的文件夹。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值