这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战
-
SpringBoot整合tomcat原理(很简单,没那么复杂)
-
SpringBoot项目在启动的时候,如果发现当前项目是一个web项目(引入了web依赖)。那么就会创建一个web版的IOC容器ServletWebServerApplicationContext。
-
在该IOC容器加载的时候会去寻找 ServletWebServerFactory的实现bean。
-
而我们自动配置中会自动配置一个ServletWebServerFactoryAutoConfiguration(Servlet工厂的自动配置类),这个自动配置会依据我们的依赖加载对应的ServletWebServerFactory工厂实现。
-
然后通过这个SerlvetWebServer工厂来创建tomcat服务器并启动。(tomcat的源码是被打包成依赖加载进项目了,我们可以通过new Tomcat()来创建Tomcat服务器,并start()启动它。不是外部启动,而是通过代码的方式启动)。
-
-
零配置原理
- 这个零配置最大的体现其实还是在tomcat和spring mvc的配置上实现了零配置。(可以看spring mvc那节)
-
自动装配的原理
-
在SpringBoot启动类上面有一个注解@ SpringBootApplication。这是一个组合注解,该注解组合了一个EnableAutoConfiguration注解。依据名字可以知道,这个就是开启自动配置的。
-
EnableAutoConfiguration的作用就是import一个AutoConfigurationImportSelector类(所有的EnableXXX的作用基本都是这个)。这个select的主要作用就是返回一堆的全限定类名,Spring会将这些类全部加载进IOC容器。
-
该Selector类里面会通过SpringFactoriesLoader去加载所有jar包中存在META-INF/spring.factories文件的配置中key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的自动配置类配置。(类似于JavaSPI机制,但是并不是哦)。
-
而我们spring-boot-autoconfigure模块中,有该配置文件,里面已经预定义好了100多条自动配置类。
-
这些自动配置类并不会全部加载,而是按需加载。
-
首先会过滤一波配置类,比如我们在SpringBootApplication注解上标注了要被排除的注解类。
-
通过如@ ConditionalClass的Conditional注解,会判断我们当前项目中是否有自动配置需要的依赖类。(我们一般结合对应的starter来导入这些类,并完成自动配置。)
-
-
后面这些配置类就会被加载并解析,将需要配置的bean都加载到Spring容器中。
-
-
如何自定义starter以及原理
-
对于那些大概率会被多个项目引用的,我们希望能够在开发中快速集成的模块,十分建议将其封装为starter
-
starter有下面几个核心组成
-
编写@ ConfigurationProperties配置类,约定项目需要的配置。
-
编写自动配置类,依据配置类的信息,来指定需要创建什么样的bean。这里面就只需要注意下用@ Conditional注解来条件注入配置类。
-
META-INF/spring.factories 下配置org.springframework.boot.autoconfigure.EnableAutoConfiguration,指定需要加载的自动配置类。
-
-
-
springboot启动流程
-
main方法会调用SpringApplication.run方法。该方法就是NEW创建一个SpringApplication对象。然后运行SpringApplication对象的run方法。
-
创建SpringApplication对象(new SpringApplication)
-
判断当前项目的类型是web还是非web的
-
去spring.factories找 ApplicationContextInitializer
-
去spring.factories找 ApplicationListener
-
这块主要目的就是判断当前项目类型,并找出所有spring.factories下面的ApplicationContextInitializer和ApplicationListener
-
-
运行SpringApplication对象(.run(args))
-
获取所有 RunListener,从所有的spring.factories找 SpringApplicationRunListener,并调用starting方法,通知对项目启动感兴趣的监听器,项目在启动中。
-
初始化Environment环境,web会创建StandardServletEnvironment环境对象。环境准备好了,会通知所有监听器环境准备完成。
-
createApplicationContext创建IOC容器,依据web还是其他的什么项目创建对应的IOC容器(一共三种,web的,正常的,reactive的)。
-
prepareContext
-
IOC容器的后置处理流程
-
调用所有的ApplicationContextInitializer的initialize方法,对ioc容器进行初始化扩展功能。
-
通知所有的监听器contextPrepared事件
-
通知所有的监听器contextLoad事件
-
-
refreshContext
-
开始正式刷新IOC容器,调用容器的refresh方法。
-
refresh方法调用到onRefresh方法的时候,在onRefresh方法执行完会调用createWebServer去容器拿到ServletWebServerFactory的实现类bean(自动配置进去的)然后来创建tomcat并启动
-
启动tomcat会自动回调ServletContainerInitializer接口实现类,从而将DIspatcherServlet这些都注入进去。
-
总结就是先初始化IOC容器,然后再onRefresh结束后,会启动tomcat并初始化SpringMVC相关的东西。
-
-
afterRefresh
- 什么都没做
-
listeners.started(context); 通知所有listener,started事件
-
callRunners 调用所有的runner类,执行他们的run方法。(就是CommandLineRunner和ApplicationRunner的实现)
-
listeners.running 通知监听器,boot项目正在运行中。
-
-
整个SpringBoot启动流程,无非就是IOC的启动流程中扩展了一些事件监听机制。以及在onRefresh方法后tomcat做初始化启动工作。
-
-
SpringBoot的一些扩展点
-
SpringApplicationRunListener
- Spring Boot启动过程中各个环节可以监听或者发布一些事件。
-
ApplicationListener
- @ EventListener注解可以监听SpringBoot项目内部的事件。
-
ApplicationContextInitializer
- 在ConfigurableApplicationContext这类型容器的refresh执行前可以做一些处理。
-
CommandLineRunner和ApplicationRunner
- 即在springboot项目启动后需要做一些什么事情。
-
-
不想用tomcat想用其他的怎么做?
-
springboot提供了三种容器:tomcat , jetty, undertow
-
springboot默认是tomcat作为servlet容器的,这是因为spring-boot-starter-web中默认依赖是tomcat,所以自动配置的时候,只会配置tomcat的servlet容器
-
如果想要换就需要在项目中先将tomcat的依赖移除掉,然后添加自己想要的容器的starter依赖。比如jetty的。
-
-
springboot的原理
- 就是springboot的启动原理