服务启动堪称Spring源码设计的答案;

一、背景说明

初学SpringBoot框架时,第一次启动服务,直呼什么鬼?只需要简单的几步配置,几个核心的注解,就可以快速实现工程的搭建和运行;

虽然从Spring框架迁移到SpringBoot框架,在初期会有很多的不适应,但是更好用的框架会快速得到认可,从而成为主流的技术选型;

对于大多数的框架或者组件来说,如果使用起来越是简便,那么其内部的封装策略就越是复杂;

比如在Spring框架更新到SpringBoot版本时,其用法的简便与内部封装的复杂性已经形成强烈的对比;再到SpringCloud微服务框架时,其封装逻辑复杂到离谱;

对于服务端的开发来说,绕不开对Spring框架的深度学习,如果单纯站在源码阅读的角度,建议先熟读SpringBoot启动流程,然后再适当扩展其他源码块;

二、SpringBoot工程

首先聊一聊阅读源码的基本思路,从一个极简的案例开始,围绕案例中的核心API作为切入点,通过对源码逻辑的断点调试,从而体会其设计的原理;

阅读SpringBoot的源码,可以从服务启动方法作为切入点,然后不断的分析启动过程涉及到的核心API和设计原理,再基于具体的启动日志去分析抽象的加载逻辑;

在看具体的源码之前,还需要说下分析思路,Spring项目中,要注意每个API所属工程与层级,然后再去分析API之间关系,核心的构造、属性、方法等;

在SpringBoot的启动类中,有两个核心的切入点,一个是类的构造方法,完成一列的初始化动作;一个是启动方法,实现应用上下文的创建和装载;

构造方法

启动方法

需要说明的是,由于SpringBoot服务启动过程涉及源码过多,所以上面的源码中只是罗列部分的核心切入点,然后围绕这些关键流程展开,分析一些常见的源码设计;

另外说明一点,以下源码的核心版本:JDK-1.8spring-5.2.4spring-boot-2.2.5,在不同的版本下源码会存在差异;

三、应用上下文

服务启动时,根据应用类型判断创建的上下文,此处启动的是基于servlet的web应用,所以也依赖相应的web服务器,默认为Tomcat;

启动方法的核心在于对应用上下文的创建、准备、刷新,应用上下文是一个十分抽象的描述,可以理解为应用运行的整体环境,其中涉及到资源加载,配置文件装配,运行服务的管理等,后续的源码分析都围绕该API展开;

ApplicationContext:应用上下文核心接口,在该接口中所有的方法都是只读模式,即只能通过Get方法进行访问;

ConfigurableApplicationContext:上下文配置扩展接口,提供了应用上下文的配置能力,生命周期的维护,以及在关闭之后的相关资源释放;

AbstractApplicationContext:上下文接口抽象实现,核心的API,对应用上下文中的公共能力做了实现;

ConfigurableWebApplicationContext:Web应用上下文配置扩展接口,提供了Web应用的上下文配置能力;

WebServerApplicationContext:Web服务上下文,创建并管理Web应用的服务器,在该流程中嵌入的是Tomcat服务;

根据应用上下文几个核心的API设计,体会Spring源码的设计思路,从顶级的接口开始,不断向下扩展并且新增方法,理解抽象实现类的逻辑,以及服务运行时所依赖的具体API;

四、资源加载

什么是资源,可以是各种类型的文件和配置,字节输入流的转换,也可以是URL资源定位,Spring框架在运行的过程中,需要依赖Resource接口实现对底层资源的访问;

Resource:资源描述的顶级接口,提供了一系列的方法,继承InputStreamSource接口,支持将资源转换为流的形式操作;

AbstractResource:资源访问的抽象实现类,这里的设计原理与AbstractApplicationContext类似,提供资源访问方法的基础实现;

ResourceLoader:资源加载的封装接口,应用下文需要依赖该接口实现资源的获取与访问;

针对不同应用场景需求,Resource接口的实现类有如下几个:FileSystemResource文件系统资源,ClassPathResource类路径下资源,InputStreamResource输入流资源等;

五、应用环境

对于Property和Environment源码设计体系,参考上述的源码模块,在思路上是相似的,此处不多描述;

应用程序的属性和环境涉及到的参数描述非常多,比较直接的手段是通过System类中的方法输出,至于信息如何加载,在StandardEnvironment类中提供了方法,可以断点查看;

六、Bean对象

基于Spring框架的应用程序中,由Spring容器负责创建,装配,设置属性,进而管理整个生命周期的对象,称为Bean对象;Bean的生命周期非常复杂,过程大致如下:实例化,属性加载,初始化前后管理,销毁;

BeanFactory:工厂类,Spring框架的核心能力,Bean容器的顶级接口,提供了一系列Bean对象的访问方法,是IOC思想和依赖注入的基础支撑;

ConfigurableBeanFactory:Bean容器可配置化接口,该扩展接口只是为了允许框架内部的即插即用和访问bean工厂的配置方法;

AbstractBeanFactory:Bean管理的抽象实现类,可以查看其内部doGetBean方法,提供Bean实例对象的获取逻辑,如果无法获取则执行创建逻辑;

七、Tomcat服务

初次启动SpringBoot工程时,最大的疑问就是可见Tomcat启动日志,但是没有显式的做服务器装配,直接启动JAR包即可,这在流程上简化了一大步;

WebServer:Web应用服务器接口,比如常用的Tomcat,Jetty,Netty等,根据应用类型选择,只提供了启动、停止、获取端口三个方法,通过WebServerApplicationContext与应用上下文相关联;

TomcatWebServer:SpringBoot框架管理内置Tomcat服务的核心类,对Tomcat生命周期的管理提供了一层包装;

Tomcat:Apache组件中轻量级Tomcat启动器,提供了Tomcat基础配置,比如默认的Port和HostName,以及生命周期管理的方法,TomcatWebServer类中调用的就是该API中的具体方法;

八、事件模型

事件驱动模型是复杂流程中的常用解耦手段,即通过事件发送和监听两个拆解动作,实现流程的分步执行,这在SpringBoot启动流程和上下文装载中更是发挥的淋漓尽致;

ApplicationEvent:应用事件基础抽象类,继承自JDK中EventObject类,具体事件会继承该类,内部声明了事件源和发生时间两个核心属性;

ApplicationEventMulticaster:应用事件广播的顶级接口,可以将指定的应用事件广播给适合的监听器;

SimpleApplicationEventMulticaster:应用事件广播接口的简单实现,可以断点该类的multicastEvent方法,查看广播时应用事件和其相应的监听器;

ApplicationListener:应用事件监听器接口,继承自JDK中EventListener接口,Spring中扩展了多种具体的事件监听器,以实现各种不同的场景需求,比如最常见的ConfigFileApplicationListener配置文件监听器;

九、配置加载

SpringBoot工程中,配置文件的管理策略非常复杂,有内部程序执行加载配置,也有外部集成的组件配置,当然最核心的就是工程的自定义配置;

ConfigFileApplicationListener.Loader:配置文件监听器的内部类,实现对工程中的配置源加载,其核心逻辑在Loader.load方法中实现,具体逻辑由相关的实现类完成;

PropertySourceLoader:配置加载的策略接口,在Spring工程中支持多种类型的文件配置,比如yml、yaml、properties、xml,需要通过文件的扩展名选择相应的加载实现类;

YamlPropertySourceLoader:加载.yml或者.yaml类型的文件,SpringBoot工程中常用的配置文件类型,最终转换成Name和Value的属性源集合,即通过PropertySource抽象类来描述;

十、数据库集成

Spring框架的强大之处还在于能够和其他组件进行简单快速的集成,比如常用的数据库、缓存、消息队列等各种类型的组件,分析内部的集成逻辑,会发现很多原理上的相似性,尤其在SpringBoot框架中,约定大于配置;

DataSourceAutoConfiguration:SpringBoot工程中数据库的自动化配置类,在配置中Hikari是默认选择的连接池,也是号称速度最快的;

DataSourceProperties:数据源配置相关的基础类,在DataSourceConfiguration配置类中,会基于参数去创建数据源对象;

HikariDataSource:Hikari连接池组件中的数据源API,描述数据源的具体信息,例如配置、连接池、状态等,具体的数据库连接逻辑是在该组件内部完成的;

基于SpringBoot集成数据库的原理,可以扩展性的看看:Redis组件的RedisAutoConfiguration配置类;Kafka组件的KafkaAutoConfiguration配置类,Elasticsearch组件的RestClientAutoConfiguration配置类,在设计原理上都有异曲同工之妙;

写在最后

从个人经验来看,想要阅读Spring框架的源码设计,需要基于应用流程先构建一个大的轮廓结构,理解设计中的常用策略和原理,然后再深入单个模块的细节逻辑,这样容易找到阅读节奏;

本文并没有涉及源码中过多的细节逻辑,只是从服务启动作为切入点,整理与开发关联性较为直接的源码模块,描述个人对于Spring源码阅读的基础思路。

十一、参考源码

应用仓库:
https://gitee.com/cicadasmile/butte-flyer-parent 组件封装:
https://gitee.com/cicadasmile/butte-frame-parent

从SpringBoot启动,阅读源码设计的更多相关文章

  1. SpringBoot启动tomcat源码解读

    一.SpringBoot自动拉起Tomcat 原文链接:http://www.studyshare.cn/blog-front/blog/details/1136 SpringBoot框架是当前比较流 ...

  2. 带着萌新看springboot源码11(springboot启动原理 源码上)

    通过前面这么多讲解,springboot原理应该也大概有个轮廓了,一些基本的配置,从客户端url到controller(配置一些要用的组件,servlet三大组件,处理器映射器,拦截器,视图解析器这些 ...

  3. SpringBoot启动注解源码流程学习总结

  4. Zookeeper_阅读源码第一步_在 IDE 里启动 zkServer(集群版)

    上篇文章Zookeeper_阅读源码第一步_在 IDE 里启动 zkServer(单机版)讲了在 idea 里以单机的方式启动zookeeper,这篇介绍一下以集群的方式启动. 集群方式启动,才会真正 ...

  5. 基于SpringBoot的Environment源码理解实现分散配置

    前提 org.springframework.core.env.Environment是当前应用运行环境的公开接口,主要包括应用程序运行环境的两个关键方面:配置文件(profiles)和属性.Envi ...

  6. 【转】使用 vim + ctags + cscope + taglist 阅读源码

    原文网址:http://my.oschina.net/u/554995/blog/59927 最近,准备跟学长一起往 linux kernel 的门里瞧瞧里面的世界,虽然我们知道门就在那,但我们还得找 ...

  7. Spring源码解析——如何阅读源码(转)

    最近没什么实质性的工作,正好有点时间,就想学学别人的代码.也看过一点源码,算是有了点阅读的经验,于是下定决心看下spring这种大型的项目的源码,学学它的设计思想. 手码不易,转载请注明:xingoo ...

  8. 【 js 基础 】【 源码学习 】源码设计 (持续更新)

    学习源码,除了学习对一些方法的更加聪明的代码实现,同时也要学习源码的设计,把握整体的架构.(推荐对源码有一定熟悉了之后,再看这篇文章) 目录结构:第一部分:zepto 设计分析第二部分:undersc ...

  9. Spring源码解析——如何阅读源码

    最近没什么实质性的工作,正好有点时间,就想学学别人的代码.也看过一点源码,算是有了点阅读的经验,于是下定决心看下spring这种大型的项目的源码,学学它的设计思想. 手码不易,转载请注明:xingoo ...

随机推荐

  1. 《HelloGitHub》第 76 期

    兴趣是最好的老师,HelloGitHub 让你对编程感兴趣! 简介 HelloGitHub 分享 GitHub 上有趣.入门级的开源项目. https://github.com/521xueweiha ...

  2. 多线程与高并发(三)—— 源码解析 AQS 原理

    一.前言 AQS 是一个同步框架,关于同步在操作系统(一)-- 进程同步 中对进程同步做了些概念性的介绍,我们了解到进程(线程同理,本文基于 JVM 讲解,故下文只称线程)同步的工具有很多:Mutex ...

  3. Canal实时解析mysql binlog数据实战

    一.说明 通过canal实时监听mysql binlog日志文件的变化,并将数据解析出来 二.环境准备 1.创建maven项目并修改pom.xml配置文件 <dependencies> & ...

  4. Dubbo源码(六) - 服务路由

    前言 本文基于Dubbo2.6.x版本,中文注释版源码已上传github:xiaoguyu/dubbo 今天,来聊点短的,服务路由Router,本文讲的是路由的调用路径,不讲路由的规则解析.想了解规则 ...

  5. ENSP 与VMware workstation 同时安装会出现AR40 或者VMware蓝屏

    前言: 你已经安装了VMware workstation,ENSP,Virtualbox,并且关闭了hyper-v,还会出现报错或者VMware蓝屏. #此处补充一条命令systeminfo 如果你看 ...

  6. 2022CISCN-satool

    2022CISCN-satool 打国赛的时候自己还并不了解LLVM PASS pwn,前几天正好学习了一下LLVM PASS pwn,于是就顺便来复现一下这道题目. 首先找到二进制文件的重写函数的主 ...

  7. django路由匹配、反向解析、无名有名反向解析、路由分发、名称空间

    目录 django请求生命周期流程图 1.Django请求的生命周期的含义 2.Django请求的生命周期图解及流程 3.Django的请求生命周期(分布解析) 路由层 1.路由匹配 2.path转换 ...

  8. KingbaseES 逻辑备份还原加密

    KingbaseEs 支持在sys_dump备份时使用key进行加密.在sys_restore时,如果没提供key,或者key值不对,将无法进行恢复. [kingbase@dbhost03 ~]$ s ...

  9. LIKE与等式查询比较

    我们知道 char 是定长类型的数据,如果数据长度小于定义的长度,会在字符串尾部加上空格.而对于空格的处理,对于等式匹配,或length等,会忽略空格.而对于like 或模式匹配,空格不能忽略. 一. ...

  10. 从零开始搭建gitea代码管理平台

    Gitea,一款极易搭建的Git自助服务.如其名,Git with a cup of tea.跨平台的开源服务,支持Linux.Windows.macOS和ARM平台.配置要求低,甚至可以运行在树莓派 ...