SpringBoot自动配置原理
前言
对于SpringBoot的使用之后,会发现它真的很方便,以前大篇幅的XML文件几乎只需要几个注解就能搞定,那么有的小伙伴肯定会有疑问,它的内部到底做了什么以至于它连XML都不需要了,今天简单的读一下源码,如果有错误理解的地方各位一定要指出来以防误导。。
进入SpringBoot内部
对比使用之前和之后我们可以看出,其实代码方面只是增加了一个启动类,那是不是也就意味着,SpringBoot能够实现零XML配置的原因就在这个启动类中。。。
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
我们都知道,SpringBoot启动类的类名上标有 @SpringBootApplication 注解意为该项目是一个SpringBoot项目,该类是SpringBoot项目的启动类,也就是项目的入口,如果忽略了这个注解该类其实就是一个普通的java类,那么我们进入这个注解来看一下它的内部到底发生了什么。。。
SpringBoot入口的内部世界
CTRL+鼠标左键单机@SpringBootApplication注解后,我们能看到在@SpringBootApplication还标注了以上注解,最上面四个是java的元注解,在这里就不多做解释了,重点关注的是最下面三个注解,也就是说,是有了这三个注解SpringBoot才实现了自动配置,这三个注解分别为:
- @SpringBootConfiguration SpringBoot配置
- @EnableAutoConfiguration 开启自动配置
- @ComponentScan 组件扫描
下面对这三种注解分别做一个解释:
@SpringBootConfiguration
继续点击它进入内部发现:
这个注解里面并没有什么内容,而是在这个注解上面又出现了一个@Configuration注解,这个注解的含义为标注该注解的类为配置类,可以看成是原来的XML配置文件被这个注解代替了,也就是说添加了@SpringBootConfiguration这个注解的类等价于添加了@Configuration这个注解的类(配置类)也就等价于原来的XML配置文件
那么这个注解的含义也就很明显了: 表示该类是一个SpringBoot配置类
@EnableAutoConfiguration
这个注解的作用很明显,就是开启自动配置,至于怎么开启的,进入这个注解中发现:
这个注解的上面还标有两个注解:
想要知道它的含义,我们继续往里面走,
紧接着我们发现,在@AutoConfigurationPackage注解上还有一个注解**@Import**,这个注解的作用是获取需要进行自动配置的包名,也就是当前启动类所在的包,然后导入该包下及其子包下的所有组件到Spring容器中,这个注解里面有一个Registrar类,进入里面看一下:
SpringBoot就是通过这个方法来获取自动配置的包名,我们在此处打个断点:
启动项目进入到断点处:看看是否能获取到包的路径,这里的快捷键是:Alt + F8
可以看到,使用这个注解之后确实获取了包路径
那么你会注意到,传入的参数metadata,它又是什么,为什么要传入它作为参数?
通过debug我们还能看出,metadata里面存放的数据其实就是标注了@SpringBootApplication注解的主配置类以及一些相关信息,那么也就是说,SpringBoot会找到主配置类然后通过主配置类所在位置得到自动配置包路径,然后扫描其中所有组件加载到Spring容器中
获取了自动配置包路径之后,具体要加载那些组件就要用到另一个注解了,这个注解作用是给Spring容器导入一些组件
在@EnableAutoConfiguration注解上还有另一个注解@Import,我们重点关注它后面的的内容,也就是
@Import(AutoConfigurationImportSelector.class)
AutoConfigurationImportSelector 这个类的作用先看名字,意思是自动配置类导入选择器,也就是说他的作用是导入选中的自动配置类到Spring容器中,那么问题来了,SpringBoot怎么知道哪些类被选中,需要自动配置?这也就引出了另一个问题,没有了XML配置文件之后,我们有很多类需要配置,像Mybaits中的SqlSessionFactory,分页使用的PageHelper等等是怎么配置的?
仔细想想会发现,未使用SpringBoot前我们是需要在XML配置文件中进行配置,然后由Spring读取后创建并管理起来的,而使用了SpringBoot之后,我们是将这些技术提供的启动器依赖起来,然后就可以使用了,到这里答案就明了了,所谓被选中的自动配置类,就是我们在pom文件里添加的启动器依赖里面对应的的那些类,也就是说,你添加了什么启动器,它就导入这些启动器对应的自动配置类
来看一下源码验证:
进入这个类中能看到一个selectImports方法,获取所有导入组件的全类名并返回,这些组件就会被添加到容器中,具体获取我们看标红线这个方法,点进去:
通过debug我们可以看出,执行该方法会给容器中导入很多的Xxxx自动配置类,也就是导入该项目需要的组件并帮我们配置好这些组件
那么他是怎么获取这些自动配置类的呢?我们看上面标红线的方法:
这里标红了一个文件路径,这个路径非常重要!!!,我们接着看
可以看出,通过多个方法的调用之后,在loadSpringFactories方法中,从一个FACTORIES_RESOURCES_LOCATION常量中获取资源,通过Properties加载资源,最后返回。这个常量的值就是我们上面提到的META-INF/spring-factories文件路径
这个目录在SpringBoot项目的外部库 External Libraries 中
点开文件我们会发现在这个文件收录了很多的自动配置类的全路径!!
也就是说自动配置类是从这里获取到类名全路径,然后进行自动配置的。
点开一个我们熟悉的WebMVC相关的配置类的看一下:
真的已经配置好了,不需要我们自己配置了
@ComponentScan
这个注解的含义为组件扫描,它的作用是扫描自动配置包下的所有标注了注解的类到容器中管理,相当于我们使用SpringBoot之前在XML配置文件中配置的组件扫描器 <context:component-scan base-package=“扫描的包路径”/>
总结
SpringBoot项目启动的时候,从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值(也就是我们的引入的启动器依赖中含有的自动配置类),然后看项目中用到了这里面的哪些类,将存在的这些类作为自动配置类导入容器中,并让其生效,而且每一个自动配置类还对应一个属性类,以Properties结尾,这些类对应了我们的SpringBoot的配置文件application.yml,就是当我们需要对SpringBoot的默认配置进行修改时,我们需要在配置文件中进行修改,然后由SpringBoot通过反射拿到修改后的值在赋给对应的Properties类的属性,我们可以在这些Properties类中看到平时yml中配置的一些相关属性
比如:
这个配置类对应web项目的相关配置
新手总结,有问题各位朋友一定要指出来,以防误导他人。。。