文章目录:
1.开始
首先肯定要说一下SpringBoot的四大核心了:
· 自动装配:简单配置甚至零配置即可运行项目
· 起步依赖:场景启动器
· Actuator:指标监控
· 命令行界面:命令行
这篇文章,我想和大家分享一下,我对自动装配这个核心的理解。
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等等。而现在不需要了,你就可以直接写一个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开启自动配置功能,这样自动配置才能生效。
那我们点到 @EnableAutoConfiguration 这个注解中,看看吧
四个元注解不说了,我们发现除此之外还有两个注解。
· @AutoConfigurationPackage :自动配置包,点进去看看,它的上面有一个@Import注解。
首先说一下:我这个项目主启动类的包路径是 com.songzihao.springboot。
Spring底层注解@Import ,给容器中导入一个组件。(利用Registrar给容器中导入一系列组件,那么它是将指定的一个包下的所有组件导入进来吗?当然不是,Debug执行我们可以看到,所导入的组件都位于主启动类所在包及其子包下)
Registrar.class 作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器;这也就是为什么SpringBoot项目创建之后新建的其他包需要方便主启动类所在包的子包中了。因为这有这样才会被扫描并加载到Spring容器中。
好了,这个@AutoConfigurationPackage注解分析完了,我们回到@EnableAutoConfiguration这个注解中,它上面还有一个 @Import({AutoConfigurationImportSelector.class}) 这个注解,翻译一下:自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:
发现这是一个类,我们主要来看源码中的这几个方法:👇👇👇
点进去这个方法,我们可以看到,在这个方法的源码中,频繁的在对 configurations 对象做一系列操作,所以我们就不得不重视起来这个configurations 对象,
它是通过调用 getCandidateConfigurations 这个方法得到的。
我们在这里打个断点看看调用完这个方法会得到什么,可以看到这里加载了大量的自动配置组件。
1. 首先利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件。
2. 调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类。
3. 利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件。
4. 从META-INF/spring.factories位置来加载一个文件。默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件。
关于第三步和第四步请继续往下看:👇👇👇
这个方法呢,首先是调用了SpringFactoriesLoader.loadFactoryNames方法,我们点进去看看这里面有什么。
如果仔细看源码了话,你会发现经常看到一个东西就是:META-INF/spring.factories,那么它里面到底有什么呢?答案在这里:👇👇👇
在这里面我们看到了很多自动配置的文件;这就是自动配置根源所在!
我们可以找点熟悉的看看,比如:RedisAutoConfiguration,它的上面有一些@Conditional相关的注解。
可以看到这些一个个的都是JavaConfig配置类,而且都注入了一些Bean,可以找一些自己认识的类,看着熟悉一下!
5.总结
1. SpringBoot启动时会加载大量的自动配置类 xxxAutoConfiguration。
2. 每个自动配置类按照条件进行生效,一旦这个自动配置类生效,那么这个它就会向容器中添加各种@Bean指定好的组件(只要我们要用到的组件在自动配置类中有,那么我们就不需要再进行配置了)。
3. 所有在配置文件中能配置的属性值都是在xxxProperties属性类中封装好了,这些值从xxxProperties属性类里面拿。这些类里面的每一个属性又是和配置文件绑定好的,我们就可以在配置文件中指定这些属性的值。
4. 定制化配置:用户可以直接通过定义@Bean替换底层的组件。
· xxxAutoConfiguration:自动配置类给容器中添加组件。
· xxxProperties:封装配置文件中可以定义的相关属性。
· xxxAutoConfiguration ---> 组件 ---> xxxProperties里面拿值----> application.properties
不知道大家有没有发现,很多需要待加载的类都放在类路径下的META-INF/Spring.factories文件下,而不是直接写死这代码,这样做就可以很方便我们自己或者是第三方去扩展,我们也可以实现自己starter,让SpringBoot去加载。现在明白为什么 SpringBoot 可以实现零配置,开箱即用了吧!