spring boot 2启动过程整理

Spring Boot 2 特性


摘自官网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 功能
  • 提供 PropertiesYaml 配置文件的解析,以及数据绑定
  • 推断上下文环境是 SERVLETREACTIVENON, 以建立相应的 ConfigurableApplicationContext 来管理 Bean 的生命周期
  • 支持可扩展 SPI 接口,包括 PropertySourceLoaderSpringApplicationRunListenerSpringBootExceptionReporterApplicationContextInitializerApplicationListenerEnvironmentPostProcessorFailureAnalyzerFailureAnalysisReporter

了解了 SpringFactoriesLoader 实现相似 java spi 的功能,咱们就能够自定义实现 SPI 的接口。实现方式:app

  1. 以 java config 形式配置托管,例如:@Component
  2. 在执行 run 返回的 ConfigurableApplicationContext 中添加(部分接口能够)
  3. 工程中新建 META-INF/spring.factories 文件,以 接口=实现 的形式存放

实现自动配置


咱们的 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 ,并执行 AutoConfigurationImportSelectorselectImports,该方法调用 SpringFactoriesLoader 读取spring.factories获取 EnableAutoConfiguration 对应的实现类。ide

方法执行栈
refresh --> invokeBeanFactoryPostProcessors --> ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry --> AutoConfigurationImportSelector.selectImports

最后会在 AbstractApplicationContext.finishBeanFactoryInitialization 初始化非懒加载的对象,完成自动化配置。

Web 服务的启动


首先咱们来看下 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();
}

总结


最后,咱们经过一图简单解答前言中提到的问题。

springboot.png

当 spring boot 启动完成后,正常状况下一次 http 请求大体会经历这样一个过程。用户输入访问地址 --> 浏览器客户端发起请求 --> web 服务(tomcat、jetty)转发请求 --> 请求处理(servlet规范、reactive规范、其余自定义的) --> 响应结果

注:第一次发博客,不免有所不足,甚至出现错误的地方,欢迎你们指正,谢谢。

相关文章
相关标签/搜索