前言
这是一个个早早就定下来的一个学习目标。再次提醒下自己2020年的学习计划:深挖spring/spring-boot源码。弄懂nio(其中代表是netty)。还有时间学习了解下es。另外每周5道力扣题。每周力扣的周赛尽可能参加。这就是我年前三个多月的计划。
其实这里不管是spring boot,还是netty也包括es,都不是说学会使用,毕竟简单的使用我都会。这里我是希望借助现在还不算繁忙的时间,学会理解底层原理,为什么这么设计等。
挺反感一个词:API调用工程师。毕竟那让我觉得我所有的付出,学习,专研,测试都喂狗了,好像是个人就能做到一样。当然了也可能确实是现阶段的我确实菜的扣脚。所以,为了摆脱这个词而奋斗!
因为这是开的第一篇spring boot源码解析,所以多说几句,鸡血也要适量的打。另外其实目前我没有看到一个很权威的spring boot源码解析是教材,所以这一块的笔记我可能是这个视频总结点东西,那个视频总结点东西。这本书上记点笔记,那本书上记点。不管是知识结构乱了,或者说有的知识点重复了都要理解。好了,下面开始正式学习了!
spring boot 简介
Spring boot本身就是用来简化Spring应用开发的。约定大于配置,去繁从简。just run就能创建一个独立的产品级别的应用。是整个Spring技术栈的大整合。J2EE开发的一站式解决方案。
Spring boot 的优点:
- 快速创建独立运行的spring项目以及主流框架集成
- 使用嵌入式的Servlet容器,应用无需打成war包。
- starters自动依赖与版本控制。
- 大量的自动配置,简化开发,也可以修改默认值。
- 无需配置XML,无代码生成,开箱即用。
- 准生产环境的运行时应用监控
- 与云计算的天然集成
Spring boot 的缺点:
其实这个也不算是缺点,怎么说的,Spring boot是基于Spring的进一层封装。所以可能很多底层的东西都藏的很深。入门是容易的,但是真出了一些非常规问题如果不熟悉Spring,可能会比较难定位问题。
环境及打包部署
这部我觉得都不配在源码分析里,但是教学视频中有,所以还是简单的说一下。spring boot 2.x以上只能用jdk8及以上。
然后打包的话就不用说了,首先spring boot的项目直接打成jar包就可以运行了。当然这个需要一个插件:
<!-- 这个插件的作用就是可以将应用打包成一个可执行的jar包 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
打成jar之后直接java -jar xxx.jar就ok了。当然我们也可以反解压回去看下这个jar,其中就有Tomcat依赖。这个也是spring boot项目能独立运行的原因。
spring boot内置tomcat
上面说了spring boot内置了Tomcat。
这个其实我反正乍一接触是觉得挺神奇的,毕竟自带tomcat本身就很方便。在以前spring的时候要把项目放到tomcat中然后启动。而现在是spring boot项目中有tomcat。这两样东西都没变,但是使用起来感觉却大不相同。
而要怎么证明Spring boot中内置了tomcat呢?最简单的办法,就是去spring boot的依赖中找啊。
查看依赖的包:

当然了,这里直接看上面jar包中lib下的依赖也行:

其实到这里也确定了spring boot自带Tomcat了。
Spring boot 是怎么实现的自带Tomcat和版本控制?
其实到这里才是重头戏。我们知道spring boot很神奇了。自带启动类和Tomcat了,但是我们要做的不仅仅是知道,而是为什么。
其实原因也挺好找的,因为有依赖,可是明明我们只导入了一个spring-boot-starter-parent。是怎么做到的依赖呢?

这里刨根问底一下,我们往下找找在哪里依赖的,首先这个parent我们都应该比较熟悉,工作中常用的父子依赖。有点类似于java中的继承:父类的包和版本,子类都继承到了。因为我们在自己的boot项目中没引入什么依赖,所以第一反应去父类找没啥问题。点进去瞅瞅:

说实话进去看个大概就会发现,这个里也没啥内容。不过还好这个还有个爸爸。继续往上刨吧:

呦呵,一进这个文件就能发现,我们想要的找到了!
我这个截图是缩进了版本的一部分,不过大家可以看看行数:快200个版本号的定义。再往下拽,好几百个依赖。其实大家想想虽说平时干什么都要引个jar之类的,但是真正我们用到过,或者说平时用的jar才多少个?就这个pom文件中的,远远超出了我们常用的了。


由此也解开了我们一个疑惑:为什么在Spring boot 项目中,大多数不必要写版本了。而上面这个pom文件,也被称为Spring boot的版本仲裁中心。
(ps:如果不存在这个仲裁中心的依赖,还是要写版本的)
spring-boot-starter
这里要单独说一下这个概念,之前我们为了让项目是一个spring boot项目,所以引入了spring-boot-starter-parent这个父项目。
刚刚我习惯性的引入了spring-boot-starter-web(可以往上翻翻我项目的pom文件截图)依赖。稍微用心观察就会发现,两个都是spring-boot-starter开头的。这仅仅是个巧合么?肯定不是的。
spring-boot-starter:是spring-boot场景启动器。具体引入什么starter后面的依赖,我们会把这个依赖用到的所有都导进来。
如果说我导入了starter-web。里面把web所有要用到的依赖都抽取出来了。引了一个starter-web,其关联的都导入了。并且版本也由spring boot直接控制。
Spring Boot将所有的功能场景都抽出取来,做成一个个的starters(启动器),只需要在项目里引入这些starter,相关场景的所有依赖都会导入进来。要用什么功能就导入什么场景的启动器。
Spring Boot自动配置
其实用过spring boot的人都知道,spring boot自带一个XXAplication类,其中带了个main方法,里面就一句话:
SpringApplication.run(XXXApplication.class, args);
并且这个类还会有一个注解:
@SpringBootApplication
先从这个注解说起:
@SpringBootApplication注解:SpringBoot应用标注在某个类上,说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用。
我们可以点进去这个注解瞅一眼到底是怎么实现的:

点进启动类注解会发现这个注解上还有一大堆注解。挺有意思的一个事。挑认识的看:Configuration应该是我们熟悉的,虽然前面加了一个SpringBoot,但是我们应该能才出来这个是什么意思,当然了这个也不用靠猜,点进去看看:

呵,不看不知道,一看吓一跳,这个注解是我们以前spring的老朋友啊。而两者的差别,也就名字不同啊。区别只不过@Configuration是spring中的。而@SpringBootConfiguration是springboot中的。(这块我觉得可以理解成一个校长一茬校服。换了校长以后虽然校服换了,但是校服里那个人却没有变)而且这个注解是向下兼容的,就是spring boot中使用spring的Configuration是可以生效的。
你以为到这就完事了么?不不不,我们继续往下刨,@Configuration又是什么?

原来这个配置注解的底层,也不过是spring的一个组件。所以说一个配置类,也不过是纳入了spring的一个bean而已。
这个一层层下往找的过程还是很有趣的,附上一个查找过程图:

到这我们把Springboot启动类注解中的一个搞明白了,还剩下一个@EnableAutoConfiguration。
其实我觉得有时候中英翻译还是很直观的。所以有时候英语确实挺重要:

这个注解的作用就是告诉Spring boot帮我们自动配置。!!!!划重点,这个注解特别重要也特别有意思!
首先按照之前的套路一直往下走,找找这个自动配置到底是啥玩意儿:


看到这其实就差不多明白这个自动注入了吧?而且也能明白为什么spring boot的启动类要在最外层了吧?因为会把这个启动类所在的包中所有的文件都扫描哟!
当然了这里其实还有一个注解:
@Import(AutoConfigurationImportSelector.class)
这个也是import注解。重点是注解里的这个类:其实我觉得有时候根据英语猜一下也是很靠谱的方式:自动 配置 引入 选择器。 这四个单词连在一起其实可以猜个大概的。当然了,猜让我们有思路,但是我们还是要用事实去说话。所以继续往下找证据:
因为spring中这些东西是可以进断点的,所以debug是一个很好的途径:

其实这个虽然教程中说到要怎么找了,但是我却没单纯的学在哪行下断点。而是简单的阅读了下这个类。里面第一个方法就是选择引入 selectImports。
然后我其实在这个方法里也下了断点的。而这个方法的里面用到的两个方法也都下了断点,最终是先进入到了这个方法中。而通过断点我们可以很容易的看出了这个方法的作用:

其实看到这些,我们大概可以知道spring boot中很多东西都不用我们配置的原因是有一套默认的配置了。当然了,为什么是这些个配置被默认导入了呢?你以为是约定好的?nonono。。这个是有缘由的:

我们在这个spring boot自动配置的依赖中,META-INF下面有个文件:spring.factories。这里面把所有要自动配置的文件名都列出来了。而
总结一下:Spring boot启动的时候从类路径下的/META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效了,帮我们进行自动配置工作。

以前spring中我们是自己写配置的。而spring boot本质上这些配置是一个不能少的。但是写的过程由 spring boot完成了。而这些全部都由一个依赖完成的。就是下面这个:
spring-boot-autoconfigure-2.3.4.RELEASE.jar
其实到这,我觉得我们大概就能明白了spring boot是在spring上封装了一层以方便我们的。其底层spring一点没变。只不过是很多个人工作由spring boot完成了而已。这一章用了大量的篇幅来说明spring boot的一键式启动。其启动类一个简单的注解包含了很多东西。其中主要包括扫描启动类所在的包而把所有的组件纳入容器。还有自动配置把很多的spring boot默认配置引入。而其内置的tomcat是能够独立运行jar的基本。
而给我们使用者的感觉,就只是一个小小的启动类注解而已。挺神奇的一个东西,层层封装,而且读懂原理也有助于我们更好的应用他。比如说现在我们就很清楚为什么启动类一定要在最外层了。同时我们也明白了为什么一点配置没有我们也可以启动并使用。
一共这块23分钟的视频,我是反复重播,暂停。用了一个多小时才理清楚思路和看明白这个使用方法。对了,我看的是b站的尚硅谷雷丰阳雷神的视频,也对老师报以崇高的敬意和感谢。
另外啰嗦几句,我这次对spring boot的学习是完全想要挖掘底层的。一些原理,为什么要这样,或者说怎么实现的之类的。这个和单纯的使用是完全脱节的。作为一个spring boot使用了两年多的码农来说,可能看spring boot快速入门一小时就能使用。但是使用和了解是不一样的。因为我之前看视频教程的时候也看到一些不太友好的弹幕。将启动注解的时候,一些人说了一些没用,老师墨迹,不实用之类的话。我个人是挺反感的。当然了我也不敢直接表达意见,只能在这里吐吐槽。我觉得想要速成可以选择别的方式。而我也是在工作中确确实实的感觉到了看源码的好处:快速的定位问题,更好的去使用,开拓我们的视野,丰富我们的思路。
有些时候人家的代码写的确实很巧妙的。这个不仅仅限于spring。前一段时间我用poi,easypoi也都觉得挺有意思。再往上sort排序的按照数据量选择不同排序方式也超出了我们平时的印象了吧?有些时候去看了就会发现代码是很有意思的一件事。我希望我们不是单纯的api接口调用,因为那没有什么意义。实现本身才是有趣的。我永远相信,出于好奇,热爱,有追求有梦想的主动学习,要远远强于迫于生计,浑浑噩噩混日子。
本篇笔记就记到这里,如果稍微帮到你了记得点个喜欢点个关注。也祝大家工作顺顺利利!
网友评论