服务启动堪称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. 2509-Druid监控功能的深入使用与配置-基于SpringBoot-完全使用 .properties配置文件

    java实现的数据库连接池有很多,c3p0,dbcp等,还有号称速度最快的HikariCP,并且springboot2.0.2版本默认使用的就是HikariCP. 为什么选用Druid呢? - 性能够 ...

  2. Modbus的设备怎么对接华为云 使用金鸽BL100只需要5步

    BL100是一款高性价比的Modbus转MQTT网关支持一键对接阿里云.华为云. BL100将Modbus串口设备的数据上传至华为云只需要简单五步 第一步.首先将Modbus的设备通过RS485接上M ...

  3. linux 安装 apache+mysql+php

    http://www.cnblogs.com/lufangtao/archive/2012/12/30/2839679.html

  4. mybatis 01: 静态代理 + jdk动态代理

    背景 有时目标对象不可直接访问,只能通过代理对象访问 图示: 示例1: 房东 ===> 目标对象 房屋中介 ===> 代理对象 你,我 ===> 客户端对象 示例2: 运营商(电信, ...

  5. vscode 源代码不能自动stage change

    前言 vscode的强大不用赘述了,当你开始使用自然就会爱上他.围绕着IDE的编写体验,有很多强大的自带或者第三方插件,可以做到,编码,git管理,甚至部署一条龙[我司就有这样的插件],让大家沉迷其中 ...

  6. layui框架图片上传至服务器

    注意:只可用于数据量较小的项目,数据量庞大的项目不要用这个,否则会造成图片数量庞大,至服务器运行速度变慢或瘫痪 HTML代码 //前端使用的是layui框架<div class="la ...

  7. python爬虫之BeautifulSoup4使用

    钢铁知识库,一个学习python爬虫.数据分析的知识库.人生苦短,快用python. 上一章我们讲解针对结构化的html.xml数据,使用Xpath实现网页内容爬取.本章我们再来聊另一个高效的神器:B ...

  8. 给博客添加个充电按钮(仿B站)

    今天我准备吧B站的充电按钮移植到本博客,开始- 上代码: HTML <html> <head> <link href="./space.8.f69f7d6f8f ...

  9. 【lwip】04-网络数据包流向

    目录 前言 4.1 TCPIP分层与lwip数据共享 4.2 协议栈线程模型 4.3 pbuf 结构体 4.3.1 pbuf的标志位flags 4.4 pbuf的类型 4.4.1 PBUF_RAM类型 ...

  10. JavaScript 设计模式及代码实现——代理模式

    代理模式 1 定义 为其他对象提供一种代理以控制对这个对象的访问 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 2 应用举例 2.1 缓 ...