摘自官网java
- Create stand-alone Spring applications
- Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
- Provide opinionated 'starter' dependencies to simplify your build configuration
- Automatically configure Spring and 3rd party libraries whenever possible
- Provide production-ready features such as metrics, health checks and externalized configuration
- Absolutely no code generation and no requirement for XML configuration
目前 spring boot 已被普遍使用,关于 spring boot 的文章更是随处可见。所以,咱们就串联琐碎的知识点,简单整理出一条线。使用spring boot 已经有一段时间了,可是有些知识点仍是比较模糊。它启动过程都干了什么?如何实现自动配置的?启动 web 应用的时候何时启动 tomcat 服务的?发起一个 http 请求会经历什么过程?react
spring boot 启动过程的源码分析网上有不少,并且比较详细,就再也不详细赘述了。有兴趣的同窗自行翻阅资料哈~web
在 spring boot 启动的时候,会根据工程的环境(主要是根据特定的类名称)肯定一个 ConfigurableApplicationContext
的上下文对象,咱们就以 AnnotationConfigServletWebServerApplicationContext
作例子。spring
// 建立ConfigurableApplicationContext,若是是servlet环境会建立AnnotationConfigServletWebServerApplicationContext context = createApplicationContext(); // 从spring.factories中获取SpringBootExceptionReporter工厂,并初始化spring boot的异常分析对象 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 刷新appContext,这里开始启动spring管理bean refreshContext(context); // afterRefresh方法是protected的空实现,咱们能够用这个钩子作一些事情 afterRefresh(context, applicationArguments);
重点关注 refreshContext
方法,这个方法强制转换对象为 AbstractApplicationContext 后执行他的 refresh
方法浏览器
protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) applicationContext).refresh(); }
常常看 spring 源码的同窗,看到这一步应该就比较熟悉了,和咱们传统的 SSM 框架同样的启动流程。tomcat
启动过程当中功能简述springboot
SpringFactoriesLoader
提供通用的工厂加载机制,具体是解析工程下全部jar包中的 META-INF/spring.factories 文件,并提供反序列化 bean 功能Properties
和 Yaml
配置文件的解析,以及数据绑定SERVLET
、REACTIVE
、NON
, 以建立相应的 ConfigurableApplicationContext
来管理 Bean 的生命周期SPI
接口,包括 PropertySourceLoader
、SpringApplicationRunListener
、SpringBootExceptionReporter
、ApplicationContextInitializer
、ApplicationListener
、EnvironmentPostProcessor
、FailureAnalyzer
、FailureAnalysisReporter
等了解了 SpringFactoriesLoader
实现相似 java spi 的功能,咱们就能够自定义实现 SPI
的接口。实现方式:app
@Component
run
返回的 ConfigurableApplicationContext
中添加(部分接口能够)接口=实现
的形式存放咱们的 spring boot 的启动类一般会使用 @SpringBootApplication
,该注解包含了@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
,而 @EnableAutoConfiguration
是实现自动配置的关键框架
... @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { ... }
在前面咱们提到 spring boot 启动会执行到AbstractApplicationContext.refresh(),以后调用ConfigurationClassPostProcessor.processConfigBeanDefinitions扫描全部的 @Import
,并执行 AutoConfigurationImportSelector
的 selectImports
,该方法调用 SpringFactoriesLoader
读取spring.factories获取 EnableAutoConfiguration
对应的实现类。ide
方法执行栈
refresh --> invokeBeanFactoryPostProcessors --> ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry --> AutoConfigurationImportSelector.selectImports
最后会在 AbstractApplicationContext.finishBeanFactoryInitialization 初始化非懒加载的对象,完成自动化配置。
首先咱们来看下 AnnotationConfigServletWebServerApplicationContext
类关系图,因为图比较大就不放出来了。
AnnotationConfigServletWebServerApplicationContext --> ServletWebServerApplicationContext --> GenericWebApplicationContext --> GenericApplicationContext --> AbstractApplicationContext
因此在执行 AbstractApplicationContext.refresh 中调用 onRefresh
时,会调用 ServletWebServerApplicationContext.onRefresh
再调用 createWebServer
// ServletWebServerApplicationContext.createWebServer private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = getServletContext(); //若是配有配置WebServer,则从BeanFactory中获取一个ServletWebServerFactory的实例 if (webServer == null && servletContext == null) { ServletWebServerFactory factory = getWebServerFactory(); this.webServer = factory.getWebServer(getSelfInitializer()); } else if (servletContext != null) { try { // 调用selfInitialize,配置servletContext,注册servletContext到spring context中,并调用ServletContextInitializer的onStartup钩子方法 getSelfInitializer().onStartup(servletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } // 初始化servletContext配置 initPropertySources(); }
最后,咱们经过一图简单解答前言中提到的问题。
当 spring boot 启动完成后,正常状况下一次 http 请求大体会经历这样一个过程。用户输入访问地址 --> 浏览器客户端发起请求 --> web 服务(tomcat、jetty)转发请求 --> 请求处理(servlet规范、reactive规范、其余自定义的) --> 响应结果
注:第一次发博客,不免有所不足,甚至出现错误的地方,欢迎你们指正,谢谢。