SpringBoot——SpringBoot四大核心之自动装配(源码解析)

Posted 张起灵-小哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot——SpringBoot四大核心之自动装配(源码解析)相关的知识,希望对你有一定的参考价值。

文章目录:

             1.开始

             2.pom文件

             3.聊聊spring-boot-start场景启动器

             4.言归正传——自动装配原理

             5.总结


1.开始

首先肯定要说一下SpringBoot的四大核心了:

  • 自动装配:简单配置甚至零配置即可运行项目
  • 起步依赖:springboot程序监控器
  • Actuator:jar包的引入,解决jar版本冲突问题
  • 命令行界面 :命令行

这篇文章,我想和大家分享一下,我对自动装配这个核心的理解。


2.pom文件

从开始学框架到现在,一直都离不开一个东西,那就是Maven,之前没有学Maven的时候,项目中需要用到哪些东西,还要拷贝jar包,这就比较麻烦。而有了Maven之后,我们都知道它的核心是 pom.xml 文件,直接在这个文件中导入依赖就可以了,非常的方便。

下面,我们来看一下SpringBoot项目创建之后的pom文件。其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件!

点进去,发现它还有一个父依赖。再点到这个父依赖中,发现它没有父依赖了。

这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;

这也就是为什么我们导入依赖的时候不需要写版本号了,因为在这里SpringBoot已经对大量依赖的版本号做了统一管理,以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本了。


3.聊聊spring-boot-start场景启动器

在我们创建一个SpringBoot项目之后,然后向其中的pom文件添加依赖的时候,我们会发现,添加的很多依赖都是以 spring-boot-start-XXX 这样的形式,我当时就按照字面意思去理解:springboot-开始-XXX的依赖。

那么,我们现在说的规范一点:spring-boot-start-XXX就是spring-boot的场景启动器。

spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件;

spring-boot-starter-thymeleaf:帮我们导入了thymeleaf模板引擎正常运行所依赖的组件;

SpringBoot就是将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter。

说的形象一点,我们之前学SSM的时候,在pom文件中加入依赖,是不是有spring-context、spring-core、spring-webmvc、mybatis-spring等等。而现在不需要了,你就可以直接写一个spring-boot-start-XXX完事了。之前SSM那种方式就是点了一份又一份的菜,而现在SpringBoot直接就是点了一个套餐,这个套餐中有很多你需要的菜名。


4.言归正传——自动装配原理

上面说了那么多,其实也是聊聊一个SpringBoot项目中常见的内容的一个理解吧。

下面我们就开始自动装配原理的分析了!!!

首先来看一下它的主启动类吧。在这个类上面,有一个 @SpringBootApplication 注解,那么它的作用就是说明这是一个Spring Boot的启动入口类,SpringBoot 就应该运行这个类的 main 方法来启动 SpringBoot 应用。

我最初呢,就以为它不就是一个psvm,然后跑了一个run方法吗?但是但是一个简单的启动类并不简单!我们来分析一下这些注解都干了什么

我们点进去看看这个 @SpringBootApplication 注解。进入这个注解:可以看到上面还有很多其他注解! 最上面的四个是Java中的元注解,就不说了,我们主要来看下面这三个注解。

  • @ComponentScan:这个注解在Spring中很重要 ,它对应XML配置中的元素(我们之前在xml文件中是不是写过一个标签<context:component-scan basepackage="XXX" />)。作用:自动扫描并加载符合条件的组件或者bean ,将这个bean定义加载到IOC容器中。
  • @SpringBootConfiguration:作用:SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类; 我们点到这个注解中看看

我们发现这个注解的上面有一个@Configuration注解,这个注解不就是表示该类是一个配置类吗?在这个注解的上面还有一个@Component注解,表示启动类本身也是Spring中的一个组件而已,负责启动应用!

  • 下面我们回到 @SpringBootApplication 这个注解中,上面已经说了两个,那么还剩一个 @EnableAutoConfiguration 这个注解,翻译一下好像是:开启自动配置功能注解。它是SpringBoot自动装配的一个核心了!!!以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置 ;@EnableAutoConfiguration这个注解就是告诉SpringBoot开启自动配置功能,这样自动配置才能生效。

那我们点到 @SpringBootApplication 这个注解中,看看吧

四个元注解不说了,我们发现除此之外还有两个注解。

  • @AutoConfigurationPackage :自动配置包,点进去看看,它的上面有一个@Import注解。

Spring底层注解@Import , 给容器中导入一个组件。

Registrar.class 作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器 ;这也就是为什么SpringBoot项目创建之后新建的其他包需要方便主启动类所在包的子包中了。因为这有这样才会被扫描并加载到Spring容器中。

好了,这个@AutoConfigurationPackage注解分析完了,我们回到@EnableAutoConfiguration 这个注解中,它上面还有一个 @Import({AutoConfigurationImportSelector.class}) 这个注解,翻译一下:自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:

发现这是一个类,那么它实现了 DeferredImportSelector 这个接口,我们点到这个接口中,发现它又继承了另一个接口,再点到这个接口中,好了,看到了一个selectImports方法,那么可以得出结论,AutoConfigurationImportSelector这个类肯定是实现这个接口并且对它其中的selectImports方法做了一个实现扩展功能,那么我们在下面的源码中看看它具体实现了什么功能?

在 selectImports 方法中调用了一个 getAutoConfigurationEntry(XXX) 方法。点到这个方法中,查看一下。

这里我们重点看红色框中的方法调用,它调用了getCandidateConfigurations方法,点到这个方法中看看。这个方法实际上是向SpringFactoriesLoader.loadFactoryNames方法中传入了一个 EnableAutoConfiguration.class 参数。

这个方法呢,首先是调用了SpringFactoriesLoader.loadFactoryNames方法,我们点进去看看这里面有什么。

可以看到这个方法最终return了另一个方法,就在下方,return的这个方法首先是创建了一个map集合,它的key是String,value是一个list集合,而再往下走,发现它读取了 META-INF/spring.factories 这样一个文件,之后是这个方法关键的三步:

  • 从当前项目的类路径中获取所有 META-INF/spring.factories 这个文件下的信息。
  • 将上面获取到的信息封装成一个 Map 返回。
  • 从返回的 Map 中通过刚才传入的 EnableAutoConfiguration.class 参数,获取该 key 下的所有值。

如果仔细看源码了话,你会发现经常看到一个东西就是:META-INF/spring.factories,那么它里面到底有什么呢?答案在这里:👇👇👇

在这里面我们看到了很多自动配置的文件;这就是自动配置根源所在!

我们可以找点熟悉的看看,比如:ThymeleafAutoConfiguration,它的上面有一些@Conditional相关的注解。

可以看到这些一个个的都是JavaConfig配置类,而且都注入了一些Bean,可以找一些自己认识的类,看着熟悉一下!

  • 一但这个配置类生效;这个配置类就会给容器中添加各种组件;

  • 这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;

  • 所有在配置文件中能配置的属性都是在xxxxProperties类中封装着;

  • 配置文件能配置什么就可以参照某个功能对应的这个属性类

所以,自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容器中。


5.总结

  1. SpringBoot启动会加载大量的自动配置类。
  2. 我们看需要的功能有没有在SpringBoot默认写好的自动配置类。
  3. 我们再来看这个自动配置类中到底配置了那些组件(只要我们要用的组件有,我们就不需要再来配置了)。
  4. 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这些属性的值。
  • xxxAutoConfiguration:自动配置类给容器中添加组件。
  • xxxProperties:封装配置文件中相关属性。

不知道大家有没有发现,很多需要待加载的类都放在类路径下的META-INF/Spring.factories 文件下,而不是直接写死这代码,这样做就可以很方便我们自己或者是第三方去扩展,我们也可以实现自己 starter,让SpringBoot 去加载。现在明白为什么 SpringBoot 可以实现零配置,开箱即用了吧!

以上是关于SpringBoot——SpringBoot四大核心之自动装配(源码解析)的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot——SpringBoot四大核心之起步依赖(自定义starter)

SpringBoot——SpringBoot四大核心之起步依赖(自定义starter)

SpringBoot四大核心之actuator

SpringBoot四大核心组件

SpringBoot四大核心组件

SpringBoot四大神器之auto-configuration