深入理解SpringBoot原理
SpringBoot特点
- SpringBoot基于约定优于配置的思想
- 两大特点:起步依赖、自动配置
- 起步依赖:就是将常用组件依赖的坐标整合到一起,在使用SpringBoot的时候无需提供常用组件的版本号。
- 自动配置:SpringBoot会自动将一些配置类的Bean注册金Ioc容器,我们只需要引入想用的功能包,SpringBoot就会自动注入这些配置Bean,我们直接使用即可。
- 优点:
- 简单、快速、方便地搭建项目;
- 对主流开发框架的无配置集成;
- 极大提高了开发、部署效率;
依赖管理
- spring-boot-starter-parent依赖作为Spring Boot项目的统一父项目依赖管理;
- spring-boot-starter-parent的底层有一个父依赖spring-boot-dependencies;
- spring-boot-dependencies该文件通过标签对一些常用技术框架的依赖文件进行了统一版本号管理,例如activemq、spring、tomcat等,这也是pom.xml引入依赖文件不需要标注依赖文件版本号的原因。
自动配置流程
- SpringBoot应用启动;
- @SpringBootApplication起作用,该注解下有两个核心注解:
- @SpringBootConfiguration注解;
- @EnableAutoConfiguration注解;
- @SpringBootConfiguration注解的作用与@Configuration注解相同,都是标识一个可以被组件扫描器扫描的配置类,@SpringBootConfiguration只是进行了重新封装命名而已;
- @EnableAutoConfiguration,该注解下有两个核心注解:
- @AutoConfigurationPackage注解;
- @lmport({AutoConfigurationlmportSelector.class})注解;
- @AutoConfigurationPackage注解主要是@lmport(AutoConfigurationPackages.Registrar.class),它通过将Registrar类导入到容器中,而Registrar类作用是扫描主配置类同级目录以及子包,并将相应的组件导入到springboot创建管理的容器中;
- @lmport(AutoConfigurationlmportSelector.class)注解主要是它通过将AutoConfigurationImportSelector类导入到容器中,AutoConfigurationImportSelector类作用是通过selectlmports方法执行的过程中,会使用内部工具类SpringFactoriesLoader,查找classpath上所有jar包中的META-INF/spring.factories进行加载,实现将配置类信息交给SpringFactory加载器进行一系列的容器创建过程。
SpringBoot执行原理(重点)
-
每个Spring Boot项目都有一个主程序启动类,在主程序启动类中有一个启动项目的main()方法,在该方法中通过执行SpringApplication.run()即可启动整个Spring Boot程序。
-
SpringApplication.run()分为SpringApplication初始化、SpringBoot项目启动两个部分;
SpringApplication实例初始化
- 判断当前webApplicationType应用的类型
- this.webApplicationType = WebApplicationType.deduceFromClasspath() 方法
- 用于查看Classpath类路径下是否存在某个特征类,从而判断当前webApplicationType类型是SERVLET应用(Spring 5之前的传统MVC应用)还是REACTIVE应用(Spring 5开始出现的WebFlux交互式应用)
- SpringApplication应用的初始化器设置
- this.setlnitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class))
- 在初始化器设置过程中,会使用Spring类加载器SpringFactoriesLoader从META-INF/spring.factories类路径下的META-INF下的spring.factores文件中获取所有可用的应用初始化器类ApplicationContextInitializer。
- SpringApplication应用的监听器设置
- this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class))
- 使用SpringFactoriesLoader从META-INF/spring.factories类路径下的META-INF下的spring.factores文件中获取所有可用的监听器类ApplicationListener。
- 设置项目main()方法启动的主程序启动类
- this.mainApplicationClass = this.deduceMainApplicationClass()
SpringBoot项目启动
- 获取并启动监听器
- this.getRunListeners(args) 和 listeners.starting() 方法主要用于获取springApplication实例初始化过程中初始化的SpringApplicationRunListener监听器并运行。
- 准备项目运行环境
- this.prepareEnvironment(listeners,applicationArguments)方法主要用于对项目运行环境进行预设置,同时通过this.configureIgnoreBeanInfo(environment)方法排除一些不需要的运行环境。
- 创建Spring容器
- 根据webApplicationType进行判断,确定容器类型,如果该类型为SBRVLET类型,会通过反射装载对应的字节码,也就是AnnotationConfigServletWebServerApplicationContext,接着使用之前初始化设置的context(应用上下文环境)、environment(项目运行环境)、listeners(运行监听器) 、applicationArguments(项目参数) 和 printedBanner(项目图标信息)进行应用上下文的组装配置,并刷新配置。
- Spring容器前置处理
- 这一步主要是在容器刷新之前的准备动作。设置容器环境,包括各种变量等等,其中包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。
- 刷新容器
- 开启刷新spring容器,通过refresh方法对整个Toc容器的初始化(包括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项目启动后会立即执行这些特定程序;