说明:spring boot版本 2.0.6.RELEASE

思绪

首先,大家认识spring boot是从@SpringBootApplication注解和org.springframework.boot.SpringApplication.run(Class<?>, String...)开始的,那么我们就从这两个方向入手一探究竟。

@SpringBootApplication注解

先来看下@SpringBootApplication的申明,如下图:

核心也就是@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan这三个注解的组合。

@SpringBootConfiguration如下,即标明被@SpringBootApplication注解标注的类本身也是spring的java config类。

@ComponentScan,配置自动扫描功能,等同xml配置的<context:component-scan>。可以指定basePackages或者basePackageClasses标明扫描的根路径,如果不设置的话默认扫描@ComponentScan注解所在类的同级类和同级目录下的所有类,也就是@SpringBootApplication所在的类,所以一般spring boot项目的入口类会放在顶层目录中,这样就可以自动扫描到项目中所有的spring配置类。

 @EnableAutoConfiguration,自动配置类,是简化spring配置的核心,spring一贯的风格凡是enable开头的注解都会配备一个@Import注解来引入一个ImportSelector。这里的@Import如下图所示:

扫盲:@Import注解作用是将values配置的class加入springIOC容器中:

如果是@Configuration的配置类,则将对应的java config产生的bean纳入spring管理;

如果是普通java类,则将该类实例化并纳入spring管理;

重点看下org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.selectImports(AnnotationMetadata)方法,返回一个string数组,内容为需要加载的类限定名。

核心是通过spring的FactoriesLoader机制加载以EnableAutoConfiguration注解全限定类名为key的class。

核心在org.springframework.core.io.support.SpringFactoriesLoader.loadSpringFactories(ClassLoader)方法中,如下图所示,其实就是在classpath下查找所有

META-INF/spring.factories文件中以EnableAutoConfiguration.getName为key的string列表。

下图就是其中一个示例:

spring.factories相关内容如下:

以直观的web容器自动配置为例:

其中的ServletWebServerFactoryAutoConfiguration和ReactiveWebServerFactoryAutoConfiguration即为根据ConditionalOnWebApplication应用类型来加载对应的webServerFactory,classpath下的自动配置webServer:

备注:ServletWebServer和ReactiveWebServer是两个路子,根据WebApplicationType走不通的路。

拿ReactiveWebServerFactoryAutoConfiguration来说,如下图所示,@Import了ConditionalOnWebApplication.Type.REACTIVE应用类型可能用到的WebServerFactory。

内部再根据对应条件创建对应的WebServerFactory。

最终org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.getWebServerFactory()以及

org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getWebServerFactory()从BeanFactory获取对应的WebServerFactory

串起来的话是在org.springframework.context.support.AbstractApplicationContext.refresh()中的onRefresh()[子类]的createWebServer创建server,finishRefresh()[子类]启动server。

好了,到这里spring boot的@SpringBootApplication注解就分析完了,跟上思路没,不要开小差哦~

SpringApplication.run分析

方法入口先创建SpringApplication对象,然后调用实例run方法,如下图。

先看看构造方法都做了些什么:

1. 推动webApplicationType

2. 通过SpringFactoriesLoader机制获取并创建ApplicationContextInitializer和ApplicationListener

3. 推断应用主class(mainApplicationClass)

这些是用于扩展用的,在整个启动过程中插入对应的扩展点,具体逻辑要看实现这些接口的具体类里面的逻辑。

我们先来看主线流程,分析源码要先把主线流程逻辑拉通,再看各个点的逻辑,由面及点,这样才不会让自己陷入其中,不明所以。

如下图所示,主线其实就是创建了一个context,prepareContext以及refresh该context。

创建context

根据之前构造方法中推动出的应用类型创建对应的context,如下图所示。

我们拿reactive类型来说,对应的context为org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext

继承关系如下:

创建没什么,就这么多,重点是下面讲的prepareContext

prepareContext

里面重点是加载beanDefinitions,而原来spring框架里面是在org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory()创建完beanFactory后loadBeanDefinitions,详见下面refreshContext的分析。

refreshContext

最终调用的是org.springframework.context.support.AbstractApplicationContext.refresh()这个方法,了解spring的人应该很清楚这个方法,我之前的spring启动过程源码分析文章也讲得很清楚了。方法内容如下:

重点看下obtainFreshBeanFactory方法,如下图所示:

里面重点是refreshBeanFactory方法,我们先看下继承关系:

而spring原有的context继承自上面那个类,如下图所示:

所以refreshBeanFactory在以前spring本身的代码中,调用的是org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory()方法,如下图所示,先销毁再创建新的beanfactory,同时加载beanDefinitions,当然,第一创建beanFactory也是在这里。其实从类名很清楚就可以看出,这个基类是支持动态刷新context的:

而spring boot继承的基类只是setSerializationId,如下图:

spring boot创建beanFactory是在org.springframework.context.support.GenericApplicationContext.GenericApplicationContext()构造方法中。

至此,spring boot 创建context已经完成,在子类org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.onRefresh()方法中创建webServer,

在finishRefresh中启动webServer:

子类重写的这两个方法在父类org.springframework.context.support.AbstractApplicationContext.refresh()方法中调用的,有没有get到?这下都串起来了吧。

完结

spring boot 源码分析的更多相关文章

  1. Spring Boot源码分析-配置文件加载原理

    在Spring Boot源码分析-启动过程中我们进行了启动源码的分析,大致了解了整个Spring Boot的启动过程,具体细节这里不再赘述,感兴趣的同学可以自行阅读.今天让我们继续阅读源码,了解配置文 ...

  2. Spring Boot源码分析-启动过程

    Spring Boot作为目前最流行的Java开发框架,秉承"约定优于配置"原则,大大简化了Spring MVC繁琐的XML文件配置,基本实现零配置启动项目. 本文基于Spring ...

  3. 精尽Spring Boot源码分析 - 序言

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  4. 精尽Spring Boot源码分析 - Jar 包的启动实现

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  5. 精尽Spring Boot源码分析 - 文章导读

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  6. 精尽Spring Boot源码分析 - SpringApplication 启动类的启动过程

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  7. 精尽Spring Boot源码分析 - 内嵌Tomcat容器的实现

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  8. 精尽Spring Boot源码分析 - 支持外部 Tomcat 容器的实现

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  9. 精尽Spring Boot源码分析 - 剖析 @SpringBootApplication 注解

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  10. 精尽Spring Boot源码分析 - Condition 接口的扩展

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

随机推荐

  1. ThreadLocal 原理及一些实现

    ThreadLocal = TL 网上讲TL原理很多,我大概说下自己的理解 TL其实是不是有点像全局的配置中心,static ConcurrentHashMap<Thread,value> ...

  2. Java的注解总结

    java 1.5开始引入了注解和反射,正确的来说注解是反射的一部分,没有反射,注解无法正常使用,但离开注解,反射依旧可以使用.Java的注解详解和自定义注解: https://blog.csdn.ne ...

  3. vue.js响应式原理解析与实现

    vue.js响应式原理解析与实现 从很久之前就已经接触过了angularjs了,当时就已经了解到,angularjs是通过脏检查来实现数据监测以及页面更新渲染.之后,再接触了vue.js,当时也一度很 ...

  4. redis 模糊删除key

    redis-cli KEYS "pattern" | xargs redis-cli DEL Redis keys命令支持模式匹配,但是del命令不支持模式匹配,有时候需要根据一定 ...

  5. 11Linux_sshd_Apache

    1.Linux系统中一切都是文件. 2.配置服务实际上就是在修改配置文件. 3.重启相应服务来加载最新的配置参数. 4.为了保证下次还生效,加入到开机启动项中.

  6. Xilinx Zynq ZC-702 开发(02)—— 通过 Xilinx SDK 调试 Linux 应用

    远程调试环境由 PC 上运行的 System Debugger(集成在 Xilinx SDK 中) 和 Zynq 板上运行的 Linux TCF Agent 共同构成, 两者通过 TCP 连接,架构图 ...

  7. linux脚本启动应用

    手动输入一些命令,启动任务会很麻烦.可以写个start.sh脚本,去执行. #!bin/sh pid=`ps -ef|grep -v grep|grep ****-1.0-SNAPSHOT.jar|a ...

  8. Unity 自定义导入时切割Sprite

    using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; us ...

  9. [Go] 开始试探一门新语言的五点思考 - Golang

    1.如果在其他语言环境中写的代码很烂,那么换一门语言很可能情况更糟,因为是涉及到基本功.工程能力和心思逻辑. 2.一定要了解语言解决的问题(比如:多核并发机制性能高.省机器.简洁易学.资料少),优势是 ...

  10. Centos7下杀毒软件clamav的安装和使用

    目录 一.yum安装 二.编译安装 2.1:下载软件包 2.2:创建clamav用户和存放病毒库目录 2.3:解压安装包 2.4:安装依赖 2.5:编译安装 2.6:配置clamav 2.7:启动cl ...