SpringBoot的自动装配和run方法

SpringBoot

关于SpringBoot,谈谈你的理解:

  • 自动装配

  • run()

SpringBoot的核心,自动装配

什么是自动装配?

SpringBoot 在启动时会扫描外部引用 jar 包中的META-INF/spring.factories文件,将文件中配置的类型信息加载到 Spring 容器,并执行类中定义的各种操作。

通过注解或者一些简单的配置就能在 Spring Boot 的帮助下实现某块功能。

首先是注解@SpringBootApplication 可以看作是@Configuration@EnableAutoConfiguration@ComponentScan 注解的集合

  • @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制
  • @Configuration:允许在上下文中注册额外的 bean 或导入其他配置类
  • @ComponentScan: 扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。如下图所示,容器中将排除TypeExcludeFilterAutoConfigurationExcludeFilter

@EnableAutoConfiguration加载AutoConfigurationImportSelector类,这个自动装配类实现了ImportSelector接口,也就实现了这个接口中的 selectImports方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中

  • 第一步

判断自动装配开关是否打开。默认spring.boot.enableautoconfiguration=true,可在 application.propertiesapplication.yml 中设置

  • 第二步 :

用于获取EnableAutoConfiguration注解中的 excludeexcludeName

  • 第 三 步

获取需要自动装配的所有配置类,读取META-INF/spring.factories

spring-boot/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factor

从下图可以看到这个文件的配置内容都被我们读取到了。XXXAutoConfiguration的作用就是按需加载组件。

不光是这个依赖下的META-INF/spring.factories被读取到,所有 Spring Boot Starter 下的META-INF/spring.factories都会被读取到。

所以,你可以清楚滴看到, druid 数据库连接池的 Spring Boot Starter 就创建了META-INF/spring.factories文件。

如果,我们自己要创建一个 Spring Boot Starter,这一步是必不可少的。

  • 第 四步

到这里可能面试官会问你:“spring.factories中这么多配置,每次启动都要全部加载么?”。

很明显,这是不现实的。我们 debug 到后面你会发现,configurations 的值变小了。

SpringBoot执行原理-run方法

每个Spring Boot项目都有一个主程序启动类,在主程序启动类中有一个启动项目的main()方法,在该方法中通过执行SpringApplication.run()即可启动整个Spring Boot程序。
问题:那么SpringApplication.run()方法到底是如何做到启动Spring Boot项目的呢?
下面我们查看run()方法内部的源码,核心代码具体如下:

img

image-20211024125702161

从上述源码可以看出,SpringApplication.run()方法内部执行了两个操作,分别是SpringApplication实例的初始化创建和调用run()启动项目,这两个阶段的实现具体说明如下:

1.SpringApplication实例的初始化创建

查看SpringApplication实例对象初始化创建的源码信息,核心代码具体如下 :

image-20211024130255885

image-20211024130304945

从上述源码可以看出,SpringApplication的初始化过程主要包括4部分,具体说明如下。

  • this.webApplicationType=WebApplicationType.deduceFromClasspath()用于判断当前webApplicationType应用的类型deduceFromClasspath()方法用于查看Classpath类路径下是否存在某个特征类,从而判断当前webApplicationType类型是SERVLET应用(Spring 5之前的传统MVC应用)还是REACTIVE应用(Spring 5开始出现的WebFlux交互式应用)
  • this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class))用于SpringApplication应用的初始化器设置。在初始化器设置过程中,会使用Spring类加载器SpringFactoriesLoader从META-INF/spring.factories类路径下的META-INF下的spring.factores文件中获取所有可用的应用初始化器ApplicationContextInitializer。
  • this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class))用于SpringApplication应用的监听器设置。监听器设置的过程与上一步初始化器设置的过程基本一样,也是使用SpringFactoriesLoader从META-INF/spring.factories类路径下的META-INF下的spring.factores文件中获取所有可用的监听器类ApplicationListener。
  • this.mainApplicationClass = this.deduceMainApplicationClass()
    用于推断并设置项目main()方法启动的主程序启动类

2.项目的初始化启动

分析完(new SpringApplication(primarySources)).run(args)源码前一部分SpringApplication实例对象的初始化创建后,查看run(args)方法执行的项目初始化启动过程,核心代码具体如下:

image-20211024130215507

image-20211024130229871

从上述源码可以看出,项目初始化启动过程大致包括以下部分:

**第一步:获取并启动监听器。**this.getRunListeners(args)和listeners.starting()方法主要用于获取SpringApplication实 例初始化过程中初始化的SpringApplicationRunListener监听器并运行。

第二步:根据SpringApplicationRunListeners以及参数来准备环境this.prepareEnvironment(listeners, applicationArguments)方法主要用于对项目运行环境进 行预设置,同时通过this.configureIgnoreBeanInfo(environment)方法排除一些不需要的运行环境。

**第三步:创建Spring容器。**根据webApplicationType进行判断, 确定容器类型,如果该类型为SERVLET类型,会通过反射装载 对应的字节码,也就是AnnotationConfigServletWebServerApplicationContext,接着使用之前 初始化设置的context(应用上下文环境)、environment(项目运行环境)、listeners(运行监听 器)、applicationArguments(项目参数)和printedBanner(项目图标信息)进行应用上下文的组 装配置,并刷新配置。

**第四步:Spring容器前置处理。**这一步主要是在容器刷新之前的准备动作。设置容器环境,包括各种变量等等,其中包含一个非常关键的操 作:将启动类注入容器,为后续开启自动化配置奠定基础。

**第五步:刷新容器。**开启刷新spring容器,通过refresh方法对整个IOC容器的初始化(包括bean资源的定位,解析,注册等 等),同时向JVM运行时注册一个关机钩子,在JVM关机时会关闭这个上下文,除非当时它已经关闭。

**第六步:Spring容器后置处理。**扩展接口,设计模式中的模板方法,默认为空实现。如果有自定义需求,可以重写该方法。比如打印一些启 动结束log,或者一些其它后置处理。

**第七步:发出结束执行的事件。**获取EventPublishingRunListener监听器,并执行其started方法,并且将创建的Spring容器传进去 了,创建一个ApplicationStartedEvent事件,并执行ConfigurableApplicationContext 的publishEvent方法,也就是说这里是在Spring容器中发布事件,并不是在SpringApplication中发布 事件,和前面的starting是不同的,前面的starting是直接向SpringApplication中的监听器发布启 动事件。

**第八步:执行Runners。**用于调用项目中自定义的执行器XxxRunner类,使得在项目启动完成后立即执行一些特定程序。其中, Spring Boot提供的执行器接口有ApplicationRunner 和CommandLineRunner两种,在使用时只需要 自定义一个执行器类实现其中一个接口并重写对应的run()方法接口,然后Spring Boot项目启动后会立 即执行这些特定程序 。

通过一个Spring Boot执行流程图,让大家更清晰的知道Spring Boot的整体执行流程和主要启动阶段:

image-20211024130712833

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值