赞
踩
SringBoot是基于Spring开发的,它本身并不提供Spring框架的核心特性及扩展功能,只是用来快速、敏捷地开发基于Spring框架的应用。换句话说,SpringBoot并不是用来替代Spring的解决方案,而是和Spring框架紧密贴合用于提升Spring开发者体验的工具。SpringBoot以约定大于配置的核心思想,默认已经配置了许多设置,多数SprinBoot应用开发时只需要少量Spring配置,同时它也集成了许多常用的第三方配置(例如Redis、MongoDB、Quartz)等,SpringBoot应用中这些第三方库几乎可以零配置开箱即用。
简单来说,SpringBoot并不算是新框架,它默认已经配置好了很多框架的使用方式,就像maven整合了很多jar包,SpringBoot整合了很多框架。
SpringBoot的主要优点:
生成一个SpringBoot项目非常方便,可以分为两种方式,一种是通过在Spring官网:https://spring.io生成项目后下载到本地,再通过IDE导入(适用于Eclipse)
再官网的Projects选项中找到Spring initializr
接下来填写好自己的项目名称、包名版本号等,右边的Dependencies可以选择项目需要添加哪些依赖,如果在此处没配置,新建项目后再往pom.xml里面加也是一样的。都填写好后点击下方的GENARATE,稍后会弹出下载提示,这就是一个SpringBoot项目了。下载完后解压,得到一个完整的项目,通过IDE导入,一个SpringBoot项目就建好了。
而如果使用IDEA的小伙伴,在IDEA中已经集成了快速生成插件,可以直接在IDEA中New-Project,然后选择Spring Initializr(注意IDEA需要是旗舰版本才支持):
可以看到该界面与官网基本无差,稍微不同的是顶部新出现了一个Server URL,这里是选择生成器的地址,一般选择官网地址:https://start.spring.io即可,但因为官网地址在国外,有时候因为网络原因官网地址会连接不上,就可以像我一样,选择国内的阿里云快速启动地址也是一样的。并且后续的选项也会是中文,这里看大家自己选择了。接下来点击next,进入到依赖选择界面:
可以看到因为我使用的是阿里云的快速启动,这个界面和官网除了中文不同以外,还多出了许多阿里云相关的技术,这里依赖大家根据需要自行选择,这里是新建一个demo项目,就先选择一个SpringWeb依赖即可,最后点击finish,项目就生成了。
默认的项目结构是这样:
不同于之前的Web项目,SpringBoot连Web服务器也封装在了项目中,默认封装的是Tomcat,一个SpringBoot项目就是一个独立的Web应用,当然如果想要更换Web服务器,或是想像之前的web开发一样,不需要内置Web服务器,也可以在pom中进行配置脱离Web服务器,这里就不细讲了。
启动类
源码中的***Application类便是SpringBoot的启动类了,通过它来启动一个SpringBoot项目,打开这个类:
发现这个类很简单,通过main方法中的SpringAppliction.run方法启动项目,在后面我们稍微对它进行分析,先启动它:
控制台中输出了一些项目启动信息后,看到最后一行Started…便是启动成功了,打开浏览器访问该项目,在没有进行任何配置时,通过localhost:8080便可访问:
因为我们没有写任何页面以及接口,所以出现了该报错信息。但项目已经成功访问了。
SpringBoot相比于传统Spring框架最大的不同就是省去了各种繁琐的配置文件编写,原因是它默认已经帮我们配置好了常用的设置,接下来简单的了解下SpringBoot是如何进行这些自动配置的,那么首先就从pom.xml文件说起:
pom
在pom的顶部可以看到一个parent父节点,表示此项目继承了其中的父工程:
而点开该工程spring-boot-starter-parent,而它还有一个父节点:
再次点开:
这次终于到底了,所以可以得出结论的是,一个SpringBoot项目的父工程实际上是spring-boot-dependencies,而根据它的名字以及查看其中的配置项不难看出:
spring-boot-dependencies这一工程中管理着许多常用依赖需要的版本,而正是因为在这里配置了这些版本号,我们在引入某些依赖的时候可以不需要写版本号,使用的便是它为我们写好的版本号。但如果我们使用的是其中没有配置到的依赖,那么就必须要写版本号了。再看回到spring-boot-starter-parent工程:
不难发现该工程中配置的是与项目相关的信息,拿图中的这一条打比方,在resuorce节点中配置了过滤指定目录src/main/resources下的yml、yaml、properties文件,而该目录下的这些文件实际上就是项目的配置文件,正因为这里与我们约定好了,所以我们得在约定好的位置、用约定好的文件格式,才能被项目识别。而其他许多的自动配置,也都是以这种约定的方式帮我们完成的。这就是约定大于配置的体现。浏览完spring-boot-starter-parent的pom,可以总结出该工程的作用:
归结成一句话,因为该父工程中默认配置的存在,我们不再需要手动配置许多诸如项目路径、资源等选项,而更专注于编码。
启动器
如果仔细看pom中的依赖,会发现许多依赖的名字都有一定规律:
他们的名字都是以spring-boot-starter-***格式命名,那么其中肯定存在一些联系,那么分别点开这两个工程:
发现他们第一个依赖都是相同的,都是spring-boot-starter,那么再点进这个工程一探究竟:
此时不难发现,该工程中包含的依赖都是一些项目所需的依赖了,比如spring-boot,类似于之前spring的核心依赖,这是springboot的核心依赖,如果再点进去看发现它实际上就是将spring的核心依赖集成在了一起。以及下面的spring-boot-autoconfigure,从名字就能看出,他是与springboot自动配置相关的依赖。该jar是SpringBoot能进行自动配置的核心,稍后我们会提到。
再次回到刚刚及的这两个工程,浏览其中的依赖,就很容易知道其作用了:
SpringBoot将所有的功能场景都抽出来,做成了类似上图中的一个个的starter供开发者使用,开发者需要何种功能,只需引入启动器即可,目前主流的功能都已经有了相关的启动器,但也有少数第三方jar并不是以该规则命名的。
主启动类
主启动类即一个SpringBoot应用启动的入口,从代码上看它非常简洁,一个注解,一个main方法,但在你启动它的一瞬间,实际上是做了许多工作的。
先从注解看起:
@SpringBootApplication:该注解的作用是标注该类是一个SpringBoot应用的启动类,通过该类的主方法启动SpringBoot启动应用。而点进该注解,发现它长这样:
首先被四个元注解修饰,这是注解类的基本,就不一一解释了。重点在后面三个注解,一一来看:
@SpringBootConfiguration
从名字来看该注解应该是与配置相关,点进去再看:
此时发现该配置类被@Configuration注解修饰了,也就是说明标注该类为一个配置类,会被加载到Spring容器中,而再点进@Configuration注解:
被@Component注解修饰,不难看出该注解的实质其实是一个组件,到这里注解也就到底了,于是回到最初的@SpringBootConfiguration注解,我们可以归纳出该注解的作用:
@EnableAutoConfiguration
同样,先从其字面意思理解,应该是与自动配置相关的注解,并且加上它之后应该是启用该功能。同样点进这个注解:
该注解中又包含了两个注解:
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
先点进@AutoConfigurationPackage注解看看:
从名字来看,能大致猜出,该注解应该是与自动配置包相关的,而在该注解中的又通过@Import注解导入了一个名为AutoConfigurationPackages配置类中的静态内部类Registrar,再点进去看看:
查看两个方法,发现中的参数都包含一个名为PackageImports的类,于是点进这个类,发现它就在下面:
下一个断点,在调试窗口中发现:
此处获取到了启动类的全类名,也就是说明,Registary类实际上是把SpringBoot的启动类所在的包进行了扫描,再依据该类上给我们的注释:
结合在网上搜索的资料,得出@AutoConfigurationPackage注解的作用:
将启动类所在的包以及子包下的组件扫描到Spring容器中,他类似于在之前 spring配置文件中的<context:component-scan base-package=“org.example”/>节点。
再看另一个注解@Import(AutoConfigurationImportSelector.class),这与上面的@Import注解类似,又导入了一个名为AutoConfigurationImportSelector的配置类,点进去这个类:
由于该类方法众多,就不一一解释了,主要看一下这个方法:
方法中第一行调用了SpringFactoriesLoader类中的loadFactoryName方法,而了解过该类的小伙伴知道,该类可以在META-INF/spring.factories配置文件中读取相应的jar,并实例化成bean,而其实现过程如下:
loadFactoryName方法需要两个参数,一个是通过反射得到的factoryType,一个是类加载器,但此处传入的是由两个方法分别返回的值:
getSpringFactoriesLoaderFactoryClass()
该方法是返回了注解类EnableAutoConfiguration,也就是我们正在探究的注解。
getBeanClassLoader()
该方法将当前类也就是自己加载到了JVM中。而在loadFactoryName方法中,又将EnableAutoConfiguration的类名传入了loadSpringFactories返回值Map中,当该类名存在时则返回,不存在则返回一个空集合。而当前类的加载器则作为参数传入了loadFactoryName方法
再查看loadSpringFactories方法:
在判断不为空后,通过类中的常量FACTORIES_RESOURCE_LOCATION获取到配置文件,也就是上面提到的,位于META-INF/spring.factories下的配置文件所在的路径,并将文件中的URL,通过UrlResource的方式获取到相应的资源,再将每个资源封装到了properties中,又通过Map将每个properties取出,最后并分隔成一个个的实现类,添加到接口中。那么这里就来看看spring.factories文件究竟包含了一些什么:
全局搜索后打开它,发现它位于:
也就是位于名为spring-boot-auotoconfigure包的下的META-INF目录下:
打开它:
发现该文件的格式都是固定的,并且从这里也能看出,该文件中记录的是常用的jar相应的url,这也就解释通了上面的方法中为什么要挨个从该文件中取出url并进行获取。那么我们再随便找几个url,看看他们的样子:
发现他们的共同点都在于用@Configuration注解修饰了,而前面也分析过了,@Configuration注解的实质就是@Component,被该注解修饰的类会以Bean的方式注入到Spring容器中。
应此总结起来,自动配置的实质是通过搜索项目中的所有
META-INF/spring.factories文件,包含该配置文件的jar会被上面的loadFactoryName方法扫描到,并进行解析,通过反射的方式实例化成一个个被@Configuration修饰的配置类,最终被Spring容器加载。
@ComponentScan
从名字看它应该使用于扫描组件的,点开它:
看来到此处就已经到底了,并且最后一个注解@Repeatable注解告诉我们,@ComponentScan这个注解在此处是可以重复使用的,而这个注解的作用其实与Spring配置文件中的
<context:component-scan base-package=“com.maple.learn” />作用类似,可以将指定路径下带有指定注解的类自动装配到bean容器里
总结
说了这么多,写的时候自己也有点晕了,那么就用简单的话小结一下自己理解的自动装配原理:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。