一、背景描述初学SpringBoot框架的时候,第一次启动服务,你到底在叫什么?只需几个简单的配置步骤和几个核心注解,即可快速实现项目的构建和运行;虽然从Spring框架迁移到SpringBoot框架一开始会引起很多不适,但更好的框架很快就会被认可并成为主流技术选择;对于大多数框架或组件来说,越容易使用,其内部封装策略就越复杂;例如,当Spring框架更新到SpringBoot版本时,其使用的简单性与内部封装的复杂性形成了强烈的对比;说到SpringCloud微服务框架,其封装逻辑复杂得离谱;对于服务端的开发,Spring框架的深度学习是绕不开的。从源码阅读的角度,建议先熟悉SpringBoot的启动流程,再适当展开其他源码块;2.SpringBoot项目首先说说阅读源码的基本思路,从一个极简的案例入手,以案例中的核心API为切入点,通过源码逻辑的断点调试,从而理解设计原理;阅读SpringBoot的源码,可以从服务的启动方法为切入点,不断分析启动过程中涉及的核心API和设计原理,再根据具体的启动日志分析抽象的加载逻辑;在看具体源码之前,需要先说说分析思路。在Spring项目中,要注意各个API的项目和层级,然后分析API之间的关系。核心SpringBoot的构造、属性、方法等;在SpringBoot的启动类中,有两个核心入口,一个是类的构造方法,完成一系列的初始化动作;另一个是startup方法,实现应用上下文的创建和加载;构造方法:启动方法:需要注意的是,由于SpringBoot服务启动过程涉及的源代码过多,以上源码只列出了一些核心入口,然后围绕这些关键流程展开分析一些常用的源码设计;另外一点,源码的核心版本如下:JDK-1.8、spring-5.2.4、spring-boot-2.2.5,不同版本下源码会有所不同;3.应用上下文服务启动时,根据应用类型判断创建的上下文,这里是基于servlet的web应用,所以也依赖于相应的web服务器,默认是tomcat;启动方法的核心是创建、准备和刷新应用上下文。应用上下文是一个非常抽象的描述,可以理解为应用运行的整体环境,涉及到资源加载、配置文件组装、运行服务的管理等,后续API的源码分析是围绕API进行的;ApplicationContext:应用上下文的核心接口,该接口中的所有方法都是只读的,即只能通过Get方法访问;ConfigurableApplicationContext:上下文配置扩展接口,提供应用上下文配置能力,生命周期维护,关闭后释放相关资源;AbstractApplicationContext:上下文接口的抽象实现,核心API,实现应用上下文中的公共能力;ConfigurableWebApplicationContext:Web应用上下文配置扩展接口,提供Web应用的上下文配置能力;WebServerApplicationContext:Web服务上下文,创建和管理Web应用服务器,嵌入在进程中的是Tomcat服务;从接口入手,继续向下扩展和添加方法,了解抽象实现类的逻辑,以及服务运行时所依赖的具体API;4.资源加载什么是资源,可以是各种类型的文件和配置,字节输入流的转换,也可以是URL资源定位。Spring框架在运行过程中,需要依赖Resource接口来访问底层资源;Resource:资源描述的顶层接口,提供一系列方法,继承InputStreamSource接口。支持将资源转为流形式的操作;AbstractResource:资源访问的抽象实现类,这里的设计原理类似于AbstractApplicationContext,提供了资源访问方法的基本实现;ResourceLoader:资源加载的封装接口,应用上下文需要依赖这个接口实现对资源的获取和访问;根据不同应用场景的需求,Resource接口的实现类有:FileSystemResource文件系统资源、类路径下的ClassPathResource资源、InputStreamResource输入流资源等;5、Property和Environment源码设计系统的应用环境,参考上述源码模块,思路类似,这里不多做说明;应用程序和环境的属性中涉及的参数描述很多,更直接的方法是通过System类中的方法输出。至于Load的信息,在StandardEnvironment类中提到提供方法,可以断点查看;六、Bean对象在基于Spring框架的应用中,Spring容器负责创建、组装、设置属性,进而管理对象的整个生命周期,称为Bean对象;Bean的生命周期非常复杂,流程大致为:实例化、属性加载、初始化前后管理、销毁;BeanFactory:工厂类,Spring框架的核心能力,Bean容器的顶层接口,提供Bean对象的一系列访问方法,是IOC思想和依赖注入的基本支持;ConfigurableBeanFactory:Bean容器可配置接口,扩展接口只允许在框架内即插即用,访问bean工厂的配置方法;AbstractBeanFactory:Bean管理的抽象实现类,可以查看其内部的doGetBean方法,提供Bean实例对象的获取逻辑,获取不到则执行创建逻辑;7、Tomcat服务第一次启动SpringBoot项目时,最大的问题是可以看到Tomcat启动日志,但是没有显式的serverassembly,直接启动JAR包。是的,这大大简化了流程;WebServer:Web应用服务器接口,如常用的Tomcat、Jetty、Netty等,根据应用类型选择,只提供启动、停止、获取端口三种方法,通过WebServerApplicationContext与应用上下文相关联;TomcatWebServer:SpringBoot框架管理内置Tomcat服务的核心类,为Tomcat生命周期的管理提供了一层封装;Tomcat:Apache组件中的轻量级Tomcat启动器,提供Tomcat的基本配置,如默认的Port和HostName,以及生命周期管理的方法,API中的具体方法在TomcatWebServer类中调用;8.事件模型事件驱动模型是复杂流程中常用的解耦方法,即通过事件发送和监听。solutionaction,实现流程的分步执行,在SpringBoot启动流程和上下文加载中发挥得淋漓尽致;ApplicationEvent:应用事件的基本抽象类,继承自JDK中的EventObject类,具体的事件会继承这个类,内部声明了事件来源和发生时间两个核心属性;ApplicationEventMulticaster:应用事件广播的顶层接口,可以将指定的应用事件广播给合适的监听器;简单应用cationEventMulticaster:应用事件广播接口的简单实现,可以打断该类的multicastEvent方法,查看广播过程中的应用事件及其对应的监听器;ApplicationListener:应用程序事件监听器接口,继承自JDK中的EventListener接口,在Spring中扩展了多种特定的事件监听器,以满足各种场景的需要,比如最常见的ConfigFileApplicationListener配置文件监听器;九、配置加载SpringBoot项目,配置文件的管理策略非常复杂,有内部程序执行加载配置,也有外部集成组件配置,当然核心还是项目的自定义配置;ConfigFileApplicationListener.Loader:配置文件监听器的内部类,实现了项目中配置源的加载,其核心逻辑在Loader.load方法中实现。具体逻辑由相关实现类完成;PropertySourceLoader:配置加载的策略接口,在Spring项目中支持yml、yaml、properties、xml等多种类型的文件配置,需要通过文件的扩展选择相应的加载实现类;YamlPropertySourceLoader:加载.yml或.yaml类型的文件,SpringBoot项目中常用的配置文件类型,最后转换为Name和Value属性源集合,由PropertySource抽象类描述;优点是可以方便快捷地与其他组件集成,比如常用的数据库、缓存、消息队列等类型的组件。通过分析内部集成逻辑,你会发现在原理上有很多相似之处,尤其是在SpringBoot框架上。约定大于配置;DataSourceAutoConfiguration:SpringBoot项目中数据库的自动配置类。配置中,Hikari是默认选择的连接池,号称速度最快;DataSourceProperties:数据源配置相关的基础类。在DataSourceConfiguration配置类中,会根据参数创建数据源对象;HikariDataSource:Hikari连接池组件中的数据源API,描述了数据源的具体信息,如配置、连接池、状态等,具体的数据库连接逻辑在组件内部完成;基于SpringBoot集成数据库的原理可以从扩展性上看:Redis组件的RedisAutoConfiguration配置类;Kafka组件的KafkaAutoConfiguration配置类和Elasticsearch组件的RestClientAutoConfiguration配置类,设计原理都差不多;我写在最后的个人经验来看,如果你想阅读Spring框架的源码设计,你需要根据应用流程构建一个大纲结构,了解设计中的常用策略和原则,以及然后深入到单个模块的详细逻辑,这样很容易找到阅读节奏;本文不涉及太多源码中的细节逻辑,而是从服务启动入手,整理开发了比较直接相关的源码模块,描述了阅读Spring源码的基本思路。11、参考源码应用仓库:https://gitee.com/cicadasmile/butte-flyer-parent组件打包:https://gitee.com/cicadasmile/butte-frame-parent
