SpringBoot基本原理一二三
一、SpringBoot能干什么
准确来说SpringBoot并不是一个框架,更不是什么SpringMVC的下一代版本,它更像是一个基于Spring的快速构建工具。
所谓的快速构建主要体现在两方面,一是各种依赖管理,二是自动化配置。
在最早之前,我们要建立一个项目,需要自己手动的导入各种所需的JAR包。下载JAR包,各个JAR包之间的依赖关系,版本的冲突问题等等非常让人头疼,后来出现了像MAVEN之类的项目构建工具,它不仅提供了仓库这样的概念,可以让我们不用满世界到处百度,还能帮我们基本实现依赖关系,版本冲突等相关问题的解决。但是它依然不够智能简单,我们在POM文件中依然需要导入一堆的JAR包,而使用了SpringBoot之后,我们只需要告诉SpringBoot,比如要做WEB开发,然后导入一个WEB相关的启动JAR包之后,SpringBoot会自动帮我们去添加相关依赖,看起来好像和MAVEN没什么本质区别,但是实际上SpringBoot让JAR包的导入,依赖管理变得更加简单。
如果说依赖管理,只是SpringBoot锦上添花的功能,那么自动化配置才是SpringBoot更吸引人的地方。
虽然这些年随着注解开发的流行,我们终于可以抛弃大量的各种乱七八糟的配置文件,而仅仅通过注解就能实现某些功能,但是大量的模板化的代码依然需要去手动配置。比如我们要使用Spring的事务管理,需要配置事务管理器,使用SpringCache,需要配置缓存管理器,以及其他各种xxxFactory,xxxTemplate,这些模板化的配置在我们的日常开发中,其实很容易发现,只是简单的粘贴复制而已,不排除某些配置可能会根据项目的情况做些修改,但是大部分情况下每个项目的这些模板化的配置都是一样的。所以SpringBoot将这些大量的模板化的配置代码给抽取了出来,通过一系列的操作,帮助我们在项目启动的时候自动完成配置。
通过SpringBoot的自动化配置,我们在开发的时候可以直接去通过依赖注入使用各种Bean,各种xxxTemplate,而无需关心它是怎么实例化,怎么管理的,最多也就是在配置类上使用@Enablexxx来开启某项功能,甚至有时候连这一步也不需要。
二、SpringBoot基本实现原理
SpringBoot的自动化配置功能看上去很神奇,但其实基本的实现原理并不是特别复杂。
在做SpringBoot开发的时候,我们都知道会有一个入口类,而这个入口类上会有一个@SpringBootApplication注解,这个注解是一个组合注解,也就是说它是由一堆其他的注解组合成的注解。在这一堆注解中有一个@EnableAutoConfiguration注解,而这个注解也是一个组合注解。
在Spring中存在各种@Enable***的注解,这些注解大体上都有开启或启用某项功能的作用,同样对于@EnableAutoConfiguration而言,它的作用就是开启自动配置。
刚才我们说过,这个@EnableAutoConfiguratin注解也是一个组合注解,也就是说它也是由一堆其他注解组合而成。在这其中有一个@Import注解,这个注解使用了EnableAutoConfigurationImportSelector类,而这个类又使用了SpringFactoriesLoader类的loadFactoryByNames方法,这个方法的主要作用就是扫描类路径下,包含有META-INF/spring.factories文件的jar包。
上面罗里吧嗦的一段总结起来就是一句话,入口类使用了@SpringBootApplication注解后,会自动扫描JAR包,并且找到包含有META/spring.factories文件的JAR包。
到这里,我们应该可以想到,如果我们自己要写一个xx.starter.jar,并且让SpringBoot帮我们完成自动化配置的话,最起码在我们的jar包中,也应该有一个META-INF/spring.factories文件。
当SpringBoot扫描出各个jar包中包含的spring.factoires文件后,就会读取其中的内容(不一定是先扫再读),然后会根据其中的xxx.xxx.xxx.EnableAutoConfiguration属性的值来决定需要配置哪些东西。
上图这个是spring-boot-autoconfigure-xxx.jar中的spring.factories文件,可以看到这个属性后面值中包含了好几个xxxxAutoConfiguration,而这些xxxxAutoConfiguration就是需要去配置的东西。
我们根据xxxxAutoConfiguration的名字,随便打开一个配置类看一下。其中一眼能看到的是两个非常熟悉的注解,@Configuration和@Bean,这两个注解可以将一个类中的方法的返回值注册为一个Bean,所以由此可知,SpringBoot先是通过spring.factories文件找到哪些东西需要完成自动化配置,然后再根据配置类的名字找到配置类,最后将配置类中配置的bean注册到容器中。
到了这一步,好像其他的注解就没什么用了,因为上述的两个注解就已经可以让SpringBoot帮我们自动配置,我们所需要的Bean了。但其实在实际的开发中,一个bean尤其是一些特殊功能类的bean的创建是需要有很多判断条件的,比如它所依赖的bean由没有被创建,它所需要的依赖JAR包有没有添加到类路径下等等,还有一些bean需要根据application.properties或其他配置文件中配置的属性,来决定要不要创建该bean或者以什么样的策略来创建该bean,总而言之剩下的注解就是用来帮助SpringBoot判断,什么样的环境条件下才会去创建哪些Bean。
SpringBoot也提供了各种@ConditionalOnxxx注解来帮助我们设定所需的环境条件。
到了这里,如果该配置类满足条件注解所要求的各种环境条件,那么就会再去判断各个创建Bean的方法是否有判断条件,是否满足,如果也满足的话就会创建对应的Bean,其实也就完成了所谓的自动化配置。
三、DEMO
如果简练的来总结的话,可以发现其实整个SpringBoot的自动化配置过程就是:扫描JAR包-》找到配置文件-》找到各种配置类-》判断各种条件-》创建各个Bean。
现在假设我们要自己创建一个starter类型的JAR包,我们希望在其他项目中引入这个JAR包之后,SpringBoot可以帮我们自动配置相关的Bean,以便让其他项目可以直接使用我们自定义JAR包所提供的功能。
第一步:创建MAVEN项目
引入自动化配置jar包:
第二步编写服务类:
这个服务类就是我们的JAR包或者说当前项目可以提供给外部其他项目所使用的功能,该服务类定义了两个属性和一个方法,我们希望当其他项目引入这个JAR包之后,可以自动将我们的这个服务类配置为BEAN,并且在使用的时候,通过依赖注入拿到这个BEAN,调用其中的方法。
在该服务类中我们定义了两个属性,这两个属性我们可以为它们设定默认值,也可以不设定,如果不设定的话,我们希望外部项目在它自己的application.properties文件中配置这两个属性的值,然后SpringBoot在创建我们的服务类Bean的时候,自动将配置文件中的属性值设置到这两个属性上。
而如何将配置文件中的属性值绑定到POJO上,推荐的做法如下:
通过@ConfigurationProperties注解中设定的prefix的值,可以将配置文件中以prefix指定的值开头的属性值,绑定到POJO的属性上。
第三步编写自动配置类
这个自动配置类就是我们要添加到spring.factories中的类,它的作用就是要告诉springboot根据我们在这个类中的限定条件,去选择是否要创造我们定义好的BEAN。
@CoditionalOnClass用来判断外部项目的类路径中存在指定类
@EnableConfigurationProperties用来将已经和配置文件属性绑定的POJO转换成一个BEAN
@ConditionalOnMissingBean用来指定当容器中不存在指定的Bean的时候再去创建Bean
第四步编写spring.factories
我们只需要创建spring.factories文件,然后在其中添加我们编写好的自动配置类的全限定名即可。
到了这一步,我们的JAR包就算全部完成了。
接下来我们去创建一个SpringBoot项目,然后将我们自己编写的JAR包引入到项目中:
然后在spring.properties文件中为指定的属性赋值:
最后在代码中调用:
可以看到,我们已经成功的调用了引入的JAR包中服务类提供的方法。
我们来梳理一下整个过程:
1)当SpringBoot项目启动后,它会去自动扫描类路径下包含有META-INF/spring.factories文件的JAR包,而我们引入的自定义的JAR包中包含了此文件,所以SpringBoot会去读取这个文件。
2)读取了META-INF/spring.factories文件后,SringBoot发现里面需要自动配置一个DemoAutoConfiguration。
3)SpringBoot会根据配置文件中这个配置类的全限定名找到这个配置类,然后根据该配置类标注的限定条件进行判断。
4)因为该项目引入的我们自定义的JAR包中,包含了我们定义的DemoService类,所以就相当于该项目的类路径中存在此类,也就是符合@ConditionalOnClass条件,接着SpringBoot又发现了@EnableConfigurationProperites注解,然后根据注解指定的值找到了DemoProperties类,这个类又标注了@ConfigurationProperties注解,所以SpringBoot会根据这个注解的prefix值去application.properties中查找对应的配置,我们现在这个项目中指定的prefix的值是autoconfigurationdemo,那么SpringBoot会在application.properties中查找以autoconfigurationdemo为前缀的值。需要注意的是在SpringBoot的配置文件中,属性的名字必须是小写且以字母开头。
找到后,SpringBoot会取将这两个值绑定到标注@ConfigurationProperties的POJO上,并且将这个POJO配置为一个BEAN。
5)回到之前的配置类中,因为我们定义了一个方法并且使用了@Bean注解和@ConditionalOnMissingBean注解,首先SpringBoot会去检查容器中是否已经存在了DemoService这个Bean,发现没有之后,会执行方法,将方法的返回值创建为一个Bean。并且在创建的过程中,会通过依赖注入拿到之前已经注册好的POJOBean,间接的读取application.properties配置的值,然后赋予给DemoService实例。
6)通过上述的步骤,一个DemoServiceBean就已经被创建好,并且这个bean还获取到了application.properties中设定的属性值,这个时候,我们在SpringBoot中,就可以像引用其他普通的Bean一样,使用该Bean。
所以综合来看,其实整个过程并不复杂,但是通过SprinBoot的自动化配置,却可以大大简化我们的开发。我们只需要引入相关的JAR包,Spring就能帮我们自动去配置相关的Bean,我们根本不需要关心它是如何去配置的,我们最多也就是在application.properties中配置一些key-value,然后就能够通过依赖注入直接去使用相关的Bean。
作者:奋斗的w
来源链接:https://blog.csdn.net/u014463199/article/details/91450428
版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。
2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。