​ 从springboot的入门案例中,我们可以体会到springboot的便捷之处,使用Spring Initializer创建一个项目,然后写一个controller层就可以运行起来,我们啥也没配置,没配置tomcat、没配置mvc、没配置spring。。。。因为springboot底层都帮我们配置好了,而springboot的精髓就在于自动配置

然后不得不提一下springboot的四大特性:

  • 自动装配
  • Starter添加项目依赖
  • Spring Boot CLI与Groovy的高效配合
  • Spring Boot Actuator

本文主要讲解前两点(重点为自动装配

Starter添加项目依赖:

先从入门案例的pom.xml开始

springboot的项目中都会存在一个父依赖,如下

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.2.RELEASE</version><relativePath/> <!-- lookup parent from repository -->
</parent>

该父项目为所有spring-boot-starter的父项目

父项目有什么用?用来做依赖管理,托管子项目,按住Ctrl+鼠标左键点进去一探究竟

点进去之后发现spring-boot-starter的父项目,还存在一个依赖。

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.3.2.RELEASE</version>
</parent>

再次点进去spring-boot-dependencies会发现下图所示:

定义着所有依赖的版本和管理

所以我们能得出第一个结论:

spring-boot-dependencies存放着SpringBoot的核心依赖,管理springboot应用里面的所有依赖版本。所以以后引入一些SpringBoot依赖的时候,不需要指定版本,但是没有在spring-boot-dependencies当中管理的需要声明版本号。

那么这些依赖是如何导进来的呢?

再回到pom.xml中,pom.xml中还导入了如下依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

怎么理解spring-boot-starter-web呢?

可以拆分为两部分来看spring-boot-starter 和web

spring-boot-starter :spring的场景启动器

springboot将所有的功能场景都抽取出来,做成一个个starters(启动器),只需要在项目中引入这些starters相关场景的所有依赖都会导入进来,而且版本会自动控制。

Starters官方解释为一系列依赖描述的组合,可以通过导入这些Starters就会有相应的依赖

官网中:

有aop面向切面编程,amqp高级消息队列。。。需要啥导啥就完事了

再点进 spring-boot-starter-web 看看,声明了以下依赖:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></dependency><dependency>    做数据校验的<groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId></dependency><dependency> <groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId></dependency>
</dependencies>

原来是帮我们导入了web模块正常运行所需要依赖的组件

这个比较简单,只是开胃菜,我们再看下一个知识点

自动配置

每次启动都要通过这个主程序来启动,这个主程序上放了一个注解@SpringBootApplication,此注解意为:标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;是我们研究的重点!!!

@SpringBootApplication
public class Springboot01HelloworldQuick03Application {public static void main(String[] args) {SpringApplication.run(Springboot01HelloworldQuick03Application.class, args);}
}

接下来的分析由概括到详细,由浅到深。

先了解大概,再逐一详细分析

点进@SpringBootApplication,发现是一个组合注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration   //表示这是一个springboot的配置类
@EnableAutoConfiguration   //开启自动配置功能
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {...
}

最重要两个注解就是@SpringBootConfiguration 和 @EnableAutoConfiguration

先看@SpringBootConfiguration

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;
}

再看@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage  //自动导包
@Import(AutoConfigurationImportSelector.class) //自动配置导入选择
public @interface EnableAutoConfiguration {...
}

大致研究的方向:

@SpringBootConfiguration:

springboot的配置类,标注在某个类上,表示这是一个springboot的配置类

再点进去看一看:

@Configuration 标注在某个类上,表示这是一个springboot的配置类

@Configuration:

这个注解我们比较熟悉,spring中的配置类,相当于之前的xml配置文件

可以给容器中注入组件。。。以前配置文件的功能都可以做

此注解 @Configuration 也可以点进去,发现也是一个组件

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {String value() default "";
}

这个简单不做深究,后面为重点

@EnableAutoConfiguration:

顾名思义:开启自动配置功能,这个注解一定和自动配置相关,点进去看一下

@AutoConfigurationPackage   //自动导包
@Import(AutoConfigurationImportSelector.class) //自动配置导入选择

这两个注解是我们研究的重点

@AutoConfigurationPackage:

点进此注解看一下

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {...
}

@Import为spring的注解,导入一个配置文件,在springboot中为给容器导入一个组件

导入的组件由AutoConfigurationPackages.Registrar.class执行逻辑来决定

再次点进去看看Registrar.class

并且可以打个断点,启动springboot,观察一下

然后可以计算一下new PackageImports(metadata).getPackageNames()的值,

选中,右键

计算结果为com.liqiliang.springboot:

new PackageImport(metadata).getPackageName()最后计算这个包名为com.liqiliang.springboot

所以可以得到如下结论:

@AutoConfigurationPackage这个注解本身的含义就是将主配置类(@SpringBootApplication标注的类)所在的包下面所有的组件都扫描到spring容器中,包名都是主配置类的

所以如果将HelloController放到com.liqiliang.springboot包外面就扫描不到了,就会报错

@EnableAutoConfiguration的另一个注解:

@Import(AutoConfigurationImportSelector.class) //自动配置导入选择

AutoConfigurationImportSelector 开启自动配置类的导包的选择器(导入哪些组件的选择器)

点进去看一下

这个类中存在方法可以帮我们获取所有的配置

先做演示,再详解

此位置打断点,为了获取configurations的值

然后重启应用

一直往下执行,注意控制台是否出现configurations的值,

点开configurations,数组长度为127

注意看文件名,后缀全为 ***AutoConfiguration

将所有需要导入的组件以全类名的方式返回,并添加到容器中

最终会给容器中导入非常多的自动配置类(xxxAutoConfiguration),给容器中导入这个场景需要的所有组件,并配置好这些组件

有了自动配置类,免去了我们手动编写配置注入功能组件等工作

详解:

所有的配置都存放在configurations中,

而这些配置都从getCandidateConfigurations方法中获取,

这个getCandidateConfigurations方法是用来获取候选的配置。

这个方法可以用来获取所有候选的配置,那么这些候选的配置又是从哪来的呢?

点进getCandidateConfigurations方法

getCandidateConfiguration方法返回的list,这个list其实是由loadFactoryNames返回的,loadFactoryNames方法执行的时候传入了两个参数,一个参数为getSpringFactoriesLoaderFactoryClass(),此参数是什么?看下图

然后看到了一个眼熟的词 --->EnableAutoConfiguration

再去loadFactoryNames方法中看看,看他带了EnableAutoConfiguration.class这个值做了什么坏事情

先是将EnableAutoConfiguration.class传给了factoryType,然后.getName( ),所以factoryTypeName值为EnableAutoConfiguration

然后调用loadSpringFactories( )方法,并且从类路径下得到一个资源

FACTORIES_RESOURCE_LOCATION值为什么?

前面成员位置定义好了

再回头看看loadFactoryNames方法的下面有一些话

如下位置 还有一些话,是一条断言

Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct."

意思是:configurations必须非空,否则就打印一段话,No auto configuration classes found in META-INF/spring.factories

所以我们有必要去找找这个文件看看

(这个文件记好了,整个J2EE的自动配置组件都在springboot-autoconfigure的jar包中

打开之后会发现里面包含了很多自动配置属性

比如点开webmvc的

然后会看到很多关于mvc的配置

那么扫描到的这些文件作用是什么呢:是把这个文件的urls拿到之后并把这些urls每一个遍历,最终把这些文件整成一个properties对象,继续看loadSpringFactories方法

然后从properties对象里边获取一些值,把这些获取到的值来加载我们最终要返回的这个结果

这个结果result为map集合,然后返回到loadFactoryNames方法中

这个factoryTypeName值为EnableAutoConfiguration

因为loadFactoryNames方法携带过来的第一个参数为EnableAutoConfiguration.class,所以factoryType值也为EnableAutoConfiguration.class,那么factoryTypeName值为EnableAutoConfiguration

那么map集合中getOrDefault方法为什么意思呢?意思就是当Map集合中有这个key时,就使用这个key值,如果没有就使用默认值defaultValue(第二个参数),所以是判断是否包含EnableAutoConfiguration

看下图,这不是包含着嘛

所以不得而知了,意为把spring-boot-autoconfigure-2.3.2.RELEASE.jar!/META-INF/spring.factories

这个文件下,EnableAutoConfiguration下面所有的组件,每一个xxxAutoConfiguration类都是容器中的一个组

件,都加入到容器中。

加入到容器中之后的作用就是用它们来做自动配置,这就是Springboot自动配置之源,也就是自动配置的开始,

只有这些自动配置类进入到容器中以后,接下来这个自动配置类才开始进行启动

那spring.factories中存在那么多的配置,每次启动时都是把它们全部加载吗?神经病吧,不现实的

我们随便点开一个类

再点开一个

是不是都有这个@ConditionalOnXXX注解,每一个类都有

@Conditional是spring底层注解,意思就是根据不同的条件,来进行自己不同的条件判断,如果满足指定的条件,那么整个配置类里边的配置才会生效。

所以又不得而知了,在加载自动配置类的时候,并不是将spring.factories的配置全量加载进来,而是通过这个注解的判断,如果注解中的类都存在,才会进行加载。

这样就实现了springboot的自动配置

小结一下:

从网上贴的流程:

SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值

将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;

以前我们需要自己配置的东西 , 自动配置类都帮我们解决了

整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;

它将所有需要导入的组件以全类名的方式返回 , 这些组件就会被添加到容器中 ;

它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;

有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;

简要概括一下自动装备:

启动类中有一个@SpringBootApplication注解,包含了@EnableAutoConfiguration代表开启自动

装配,@EnableAutoConfiguration注解会去spring-boot-autoconfigure工程下寻找 META-

INF/spring.factories 文件,这个文件中列举了所有自动装备类的清单,有一百多个,然后自动读取里

面的自动装配配置类清单。

但是这些类不会全部加载,很显然这样非常不合理。但是因为有@ConditionalOn条件注解,满足

一定条件配置才会生效 如: @ConditionalOnClass(某类.class) 工程中必须包含一些相关的类时,

配置才会生效。所以说当我们的起步依赖中引入了一些对应的类之后,自动装备的条件满足了,自

动装备才会被触发。

本人刚接触springboot,草草的做了这么一个自动配置原理分析。有些表述不清楚或错误的地方请见谅。

最后说一句,springboot流弊!!!

唯有努力,人生没有白走的路,每一步都算数

Springboot入门案例教程相关推荐

  1. springboot 入门详细教程 源码

    转载知乎文章 gitee官方教程+开源项目 Gitee ​ 已认证的官方帐号 1,303 人赞同了该回答 推荐以 Spring Boot 教程与 Spring Cloud 教程的详细开源项目 &quo ...

  2. 大厂必备!springboot入门菜鸟教程,面试资料分享

    在这里分享一份 [mybatis从入门到精通] 的强力教程,定能够助你一臂之力. Mybatis基本介绍 ORM和MyBatis 对象/关系数据库映射(ORM) 基本映射方式 流行的ORM框架简介 目 ...

  3. springboot入门系列教程|第九篇:springboot实现图片上传与显示(附源码)

    前言## 上一篇我们介绍了springboot如何实现自定义拦截器配合注解使用,那么这篇我们将介绍springboot实现图片上传的功能. 目录## 文章目录 前言## 目录## 项目创建### 项目 ...

  4. SpringBoot入门案例

    一:基础入门 1,创建maven工程 2,添加SpringBoot的起步依赖 <parent><groupId>org.springframework.boot</gro ...

  5. 数学建模学习(67):XGBoost分类模型详细入门案例教程

    一.案例介绍 本案例对葡萄酒类进行分类,使用XGBoost模型实现,该数据来源:酒类. 数据集信息: 这些数据是对意大利同一地区种植但来自三种不同品种的葡萄酒进行化学分析的结果.该分析确定了三种葡萄酒 ...

  6. C语言入门案例教程:输出乘法口诀表

    1.代码的书写逻辑 写代码之前要先想一下代码的逻辑,这样在写的过程中思路会更清晰 比如本案例要输出一个乘法口诀表,这里先将输出结果放出来以便分析 首先是直观的分析:它是一个九行九列的表,每一层都是等式 ...

  7. Java实例开发教程:SpringBoot开发案例

    最近在做邮件发送的服务,正常来说SpringBoot整合mail还是很方便的,然而来了新的需求:A请求使用邮箱C发送,B请求使用邮箱D发送,也就是说我们需要配置两套发送服务. 单实例 首先我们来看下单 ...

  8. 视频教程-SpringBoot实战教程:SpringBoot入门及前后端分离项目开发-Java

    SpringBoot实战教程:SpringBoot入门及前后端分离项目开发 十三,CSDN达人课课程作者,CSDN 博客作者,现就职于某网络科技公司任职高级 Java 开发工程师,13blog.sit ...

  9. springboot 入门教程(4)--web开发(spring mvc和Thymeleaf模板,带源码)

    2019独角兽企业重金招聘Python工程师标准>>> 首先回顾下前几篇的内容:springboot 入门教程(1),springboot 入门教程-Thymeleaf(2), sp ...

最新文章

  1. R语言使用plotly绘制3D散点图实战
  2. Ubuntu 调试的时候,不能查看变量值
  3. TensorFlow全新的数据读取方式:Dataset API入门教程
  4. C++ String转int
  5. [转载]AXIS学习笔记
  6. 【渝粤教育】国家开放大学2019年春季 776员工招聘与管理 参考试题
  7. linux硬盘类型怎么选,如何选择linux系统安装类型
  8. C 非标准库(conio.h)
  9. 机器学习Scikit-Learn基本操作实战
  10. 卫生纸玫瑰花折法5步_手工教程:做一个漂亮的玫瑰花捧花,用折纸表达我喜欢你...
  11. linux 内网共享文件夹_linux局域网文件共享服务器
  12. 微信js-sdk+JAVA实现分享接口
  13. 淘宝API如何获取商品详情信息|sku|价格|店铺|优惠券|运费信息,淘宝商品详情API接口
  14. 利用Python3中turtle的绘制超立方体。
  15. 大白菜u盘系统linux系统,大白菜超级u盘启动盘制作工具win7用U盘在Mac OS X中安装Windows7系统...
  16. silvaco学习日记(四)
  17. jzoj6374. 【NOIP2019模拟2019.10.04】结界[生与死的境界]
  18. 软件工程——软件实现总结
  19. 推荐一个220V控制12V的电路板继电器-220v降压控制继电器
  20. 2021-10-13爬虫requests总结

热门文章

  1. 2023美赛思路 | 2023美赛C题Matlab代码
  2. 软件工程n!程序流程图
  3. MySQL取别名(应该取有意义的别名)
  4. 如何获取微信小程序中动态渲染的列表中的某一个数据
  5. CSS小技巧-为内盒子添加margin-top时,会带着父盒子一起下来,如何解决?
  6. xmms安装配置工作记录
  7. Java实现 蓝桥杯VIP 算法训练 删除多余括号
  8. 设计一个形状类(接口)Shape
  9. 读计算机专业广东那间学校好,读计算机专业广东省中职3+2学校那个好
  10. 多晶材料切削的晶体塑性有限元仿真