SpringBoot成长记2从Hello

北京白癜风怎么治疗 http://pf.39.net/bdfyy/bdfal/
文章配图

上一节我们提到过,认识一个新技术的时候,通常是从一个入门的HlloWorld开始,之后阅读它的一些入门文档和书籍、视频,从而掌握它的基本使用。

这一节我就来带大家从HlloWorld开始,先摸清楚SpringBoot的核心脉络,之后再来逐步分析透彻SpringBoot,从而精通它。

从搭建HlloWorld入口开始分析SpringBoot

首先我们从官方的文档中搭建出一个2.2.2版本的SpringBoot,增加了两个startr,mybatis-plus-boot-startr、spring-boot-startr-wb,使用Mavn进行项目和依赖管理,配置一个本地的mysql。相信这个对你们来说,都比较简单,我就不一一进行赘述了。

经过上面的基本搭建,你就会有类似一个下面的一个SpringBootHlloWorld级别的入口。

packagorg.mfm.larn.springboot;importorg.mybatis.spring.annotation.MapprScan;importorg.springframwork.boot.SpringApplication;importorg.springframwork.boot.autoconfigu.SpringBootApplication;

MapprScan("org.mfm.larn.springboot.mappr")

SpringBootApplicationpublicclassLarnSpringBootApplication{publicstaticvoidmain(String[]args){SpringApplication.run(LarnSpringBootApplication.class,args);}}

通过上一节你知道SpringBoot定义了一个SpringApplication的wb应用启动流程,入口通过一个java-jar的命令,执行main函数启动一个JVM进程,运行内部的tomcat监听一个默认的端口,提供wb服务。

文章配图

整个过程中第一个最关键的就是SpringBoot定义的SpringApplication,我们一起先来看下它是怎么创建nw的。

SpringApplication的创建时核心组件图

SpringApplication的创建时的代码分析

在上面的示例代码中,main方法执行了SpringApplication的run方法,如下:

publicstaticConfigurablApplicationContxtrun(Class?primarySourc,String...args){turnrun(nwClass?[]{primarySourc},args);}publicstaticConfigurablApplicationContxtrun(Class?[]primarySourcs,String[]args){turnnwSpringApplication(primarySourcs).run(args);}

run方法核心入参就是main函数所在类+main函数args的参数,之后就直接创建了一个SpringApplication对象。让我们一起来看看这个SpringBoot定义的概念怎么创建的,创建时的核心组件又有哪些呢?

publicSpringApplication(Class?...primarySourcs){this(null,primarySourcs);}publicSpringApplication(RsourcLoadrsourcLoadr,Class?...primarySourcs){this.sourcLoadr=sourcLoadr;Assrt.notNull(primarySourcs,"PrimarySourcsmustnotbnull");this.primarySourcs=nwLinkdHashSt(Arrays.asList(primarySourcs));this.wbApplicationTyp=WbApplicationTyp.dducFromClasspath();stInitializrs((Collction)gtSpringFactorisInstancs(ApplicationContxtInitializr.class));stListnrs((Collction)gtSpringFactorisInstancs(ApplicationListnr.class));this.mainApplicationClass=dducMainApplicationClass();}

SpringApplication的创建时核心脉络

SpringApplication的创建核心脉络比较简单:

1)RsourcLoadr指明资源加载器,这个暂时不清楚是啥东西,默认是个null。

2)wbApplicationTyp推断当前wb应用类型,通过一个dducFromClasspath方法推断出的。

3)之后设置了stInitializrs、stListnrs两个列表,分别是一堆Initializr和Listnr,都是通过gtSpringFactorisInstancs方法获取的。

4)通过primarySourcs、mainApplicationClass记录了启动主要资源类,也就是之前HlloWorld中的LarnSpringBootApplication.class。

上面是我第一次看这个类的一个脉络后,脑中得到的结果。

文章配图

你第一次看这里,肯定什么都不清楚,不知道每个变量有什么用,是干嘛的,没关系的,第一次,你只要熟悉它的脉络就可以。知道这里设置了两个集合变量Initializr和Listnr,可以设置sourcLoadr,标记了一些类型和类,这就够了。

之后你有时间,再挨个去了解每个变量或者组件的作用就可以了,这个不还是先脉络后细节的思想,是吧?

SpringApplication的创建时的细节分析

你可以慢慢拆解上面的每一步,单独看看每一个组件大体是作什么的,这个就是细节的研究,可以一步一步来。

你可以研究下RsourcLoadr是个啥?你可以看它的类注解后可以发现,这个RsourcLoadr类负责使用ClassLoadr加载ClassPath下的class和各种配置文件的。(如果你不知道JVM的ClassLoadr机制,主要加载什么,可以自己去baidu、googl了解下)。这里你可以进一步思考下,它设计成了一个接口,可以实现不同的类加载器来加载资源。

wbApplicationTyp如何被推断的?就是根据几个静态变量定义的类全限定名称,根据classPath下是否存在对应的类,来推断出类型,使用了wb-startr。默认推断出为Srvlt类型的应用。

至于primarySourcs、mainApplicationClass这个两个变量记录了LarnSpringBootApplication.class,大体是为了之后扫描自动配置等考虑的,表示从什么包名的哪一个类下启动的。

最后两个集合变量Initializr和Listnr如何设置的,这块比较值得研究下。

基本原理是通过ClassLoadr扫描了classPath下所有META-INF/spring.factoris这个目录中的文件,通过指定的factoryTyp,也就是接口名称,获取对应的所有实现类,并且实例化成对象,返回成一个list列表。

比如factoryTyp=ApplicationContxtInitializr就返回这个接口在META-INF/spring.factoris定义的所有的实现类,并实例化为一个列表ListApplicationContxtInitializr。

ApplicationListnr同理,获取到了ListApplicationListnr一个集合。

这里面其实有很多细节,使用了类加载器、缓存机制,反射机制等,有兴趣的同学可以仔细研究下。

这里以我们抓大放小思想,概括成一句话:通过工具方法通过classLoadr获取classPath指定位置某个接口所有实现类的实例对象列表。

这里获取的是ApplicationContxtInitializr、ApplicationListnr这两个接口的实例对象列表。

细节中可以学到知识,脉络中一样可以学到知识,这个思想你一定要慢慢有。抓大放小的意思,更多的是让你知道重点和关键点,而不是让你丢弃细节,这两者并不冲突,这个一定要注意。

最后这里细节分析,画一个简单组件图小结下:

文章配图

SpringApplicationRun方法的脉络分析

熟悉了SpringApplication的创建,接着我们该分析它的run方法了。

其实之前一节,我们介绍过SpringApplication的启动流程。就是高度概括了run方法的核心脉络,run方法的核心其实核心就是下图蓝色的部分:

文章配图

run方法脉络可以主要概括为:

1)自动装配配置

2)Spring容器的创建

3)wb容器启动(Tomcat的启动)

然而在run方法的执行过程,肯定不会这么简单,过程中还掺杂了很多杂七杂八的逻辑,其中有意思的扩展点,也有值得吐槽的坑。这是每个框架都会有的优势劣势吧。我们先大体摸一下run方法的脉络,给大家介绍几个术语,不然之后可能会看不懂代码细节。

SpringApplicationRun方法的脉络进一步分析

要想进一步分析run方法的脉络,首先需要熟悉几个术语,就有点像DDD的通用语言似的,懂了这些语言,理解SpringBoot和Spring才会更得心应手。

术语普及Contxt/BanFactory/Environmnt

ConfigurablApplicationContxt,容器通常称为ApplicationContxt或者BanFactory,contxt也简称为容器。ApplicationContxt包装了BanFactory,封装更高级的API而已。

ConfigurablEnvironmnt,是配置文件的抽象,有关什么proprtis或者yml等配置文件的ky-valu值,都会封装成这个类的某个实现类。

熟悉了这些术语后,我们看一起看下SpringApplication的run方法代码。

publicConfigurablApplicationContxtrun(String...args){StopWatchstopWatch=nwStopWatch();stopWatch.start();ConfigurablApplicationContxtcontxt=null;CollctionSpringBootExcptionRportrxcptionRportrs=nwArrayList();configuHadlssProprty();SpringApplicationRunListnrslistnrs=gtRunListnrs(args);listnrs.starting();try{ApplicationArgumntsapplicationArgumnts=nwDfaultApplicationArgumnts(args);ConfigurablEnvironmntnvironmnt=ppaEnvironmnt(listnrs,applicationArgumnts);configuIgnoBanInfo(nvironmnt);BannrprintdBannr=printBannr(nvironmnt);contxt=catApplicationContxt();xcptionRportrs=gtSpringFactorisInstancs(SpringBootExcptionRportr.class,nwClass[]{ConfigurablApplicationContxt.class},contxt);ppaContxt(contxt,nvironmnt,listnrs,applicationArgumnts,printdBannr);fshContxt(contxt);aftrRfsh(contxt,applicationArgumnts);stopWatch.stop();if(this.logStartupInfo){nwStartupInfoLoggr(this.mainApplicationClass).logStartd(gtApplicationLog(),stopWatch);}listnrs.startd(contxt);callRunnrs(contxt,applicationArgumnts);}catch(Throwablx){handlRunFailu(contxt,x,xcptionRportrs,listnrs);thrownwIllgalStatExcption(x);}try{listnrs.running(contxt);}catch(Throwablx){handlRunFailu(contxt,x,xcptionRportrs,null);thrownwIllgalStatExcption(x);}turncontxt;}

上面的代码,主要就是执行了一堆方法,可以从方法名字看出,都是围绕Contxt、Environmnt这些术语。也就是围绕容器和配置文件组织的逻辑。

在整个Spring容器的创建,刷新,刷新之后穿插了很多逻辑。

另外,SpringBoot整个run方法中有几个很关键扩展点,设计SpringApplicationRunListnrs、Runnrs等扩展入口。容器创建、刷新等也要各自的扩展点,对容器的增强扩展,如banFactoryPostProcssor,对Ban的增加扩展,如banPostProcssor。然而这些都是后话了。

我直接用一张图给大家概括了,上面run方法脉络:

(*黑色是直观的看出来的扩展逻辑,白色是run方法每个方法的字面理解,只是每一步有很多扩展点和做的事情比较多,让你感觉会有点云里雾里的。蓝色部分,概括了核心逻辑。也就是SpringBoot启动,说白了我们核心就是要找到这三点:自动装配配置、Spring容器的创建、wb容器启动。)

文章配图

这时候你一定要学会抓大放小的思想,之后带着这3个关键步骤,去理解SpringBoot,其他的实现可以单独来研究分析它的设计思路,比如各个扩展点的设计是如何考虑的,我们可以参考借鉴哪一些。这才是学习SpringBoot最最该学习的。

概括下就是,当一个技术看着比较复杂时,你应该顺着核心脉络理解原理,学习各个细节的亮点设计思想。不要陷入某一个细节,多思考才最重要。大家一定要记住这一点,在后续的成长记中,我会逐步带大家体验这一点的。

小结

好了,简单小结下。

主要思想学习了:

1)先脉络后细节的思想,抓大放小的思想,排除不重要的,分析最主要的。

2)细节中可以学到知识,脉络中一样可以学到知识,这个思想你一定要慢慢有。抓大放小的意思,更多的是让你知道重点和关键点,而不是让你丢弃细节,这两者并不冲突,这个一定要注意。

3)多思考才最重要。顺着核心脉络理解原理,学习各个细节的亮点设计思想,千万不能陷入知识本身。

主要知识学习了:

今天我们主要看了下SpringApplication的创建,它的核心组件有哪些,创建后执行的run方法,到底做了些什么,脉络是怎么样的。

熟悉了这些脉络,剩下的就简单了,逐步分析每个细节,看看每个细节有些值得我们学习的点,又有哪一些不太适合的点。

我们下期再见!

本文由博客群发一文多发等运营工具平台OpnWrit发布




转载请注明:http://www.aierlanlan.com/tzrz/5030.html