在hello world程序中可以看到,因为有@SpringBootApplication注解所以我们什么都不需要写就可以拥有web开发能力,那么这背后的原理是什么,SpringBoot的自动配置功能如何实现的?
@SpringBootApplication
public class SpringbootdemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootdemoApplication.class, args);
}
}
1.@SpringBootApplication注解的组成
点进去可以发现此注解由三个注解组成,其中@SpringBootConfiguration注解表示被标注的类是一个配置类,@ComponentScan负责将指定的类注册到容器中,因此提供了自动配置功能的是@EnableAutoConfiguration。
@Configuration
public @interface SpringBootConfiguration {
进入@EnableAutoConfiguration注解,可以发现它是由两个注解组成的
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
@AutoConfigurationPackage
查看此注解发现它使用@Import注解导入了一个类:AutoConfigurationPackages.Registrar.class
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
进入此类后发现它重写了两个方法
它会调用registerBeanDefinitions方法注册组件,在此方法上打上断点后启动容器,执行register方法,此时它会判断容器中是否存在AutoConfigurationPackage类,如果不存在则将其注入到容器中,因此自动配置功能不是这个注解提供的。
2.获取配置类的过程
@Import(AutoConfigurationImportSelector.class)
排除掉上一个注解后只剩下导入的这个类了,因此该类肯定提供了自动配置功能,在代码中可以看到,在调用了getAutoConfigurationEntry方法后会返回很多个XXXConfiguration
这些返回的配置就是目前项目中已经生效的自动配置,因此核心内容就在于getAutoConfigurationEntry方法是如何实现的了
getAutoConfigurationEntry方法
进入该方法并加上断点后会发现,当运行了getCandidateConfigurations方法后就会获取到很多个XXXConfiguration,后面的代码就是根据配置过滤需要生效的自动配置了,那么现在的核心转移到了getCandidateConfigurations方法
getCandidateConfigurations方法
进入该方法后发现参数autoConfigurationMetadata中已经包含了所有的自动配置类,因此核心方法应该在参数的传递上,本方法主要的作用是过滤不符合要求的自动配置,最后返回需要激活的配置类
getAutoConfigurationMetadata方法
返回查看process方法后发现获取参数的方法为getAutoConfigurationMetadata,进入此方法发现它调用了loadMetadata方法
在loadMetadata方法中它传递了一个值为META-INF/spring-autoconfigure-metadata.properties的路径
打开该文件发现它定义了许多的键值对,并且除去第一行注释后它的行数和我们获取的到数据总数是一样的
最后经过重重过滤后返回的就是需要生效的配置类了
3.XXXAutoConfiguration原理
到目前为止已经知道了SpringBoot通过AutoConfigurationImportSelector类获取到了spring-autoconfigure-metadata.properties文件中的所有键值对,并对这些数据进行了过滤,那么它需要这些字符串有什么用呢
本次讲解常用的WebMvcAutoConfiguration类具体做了什么,其他的XXXAutoConfiguration原理基本类似
根据该类上加的注解可以看到执行此类需要满足的条件,其中Conditional*表示只有当容器中满足某个条件时才加载该配置类
里面主要的代码就是满足条件后向容器中注册bean,或者是内置的配置类
我们以WebMvcAutoConfigurationAdapter类为例进行研究
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
它使用@EnableConfigurationProperties注解导入了WebMvcProperties.class, ResourceProperties.class两个类,该注解的含义是将properties或yml配置文件中的属性和对应的Properties类中的字段绑定
比如WebMvcProperties类中用@ConfigurationProperties(prefix = “spring.mvc”)标注了它的前缀,而此类中存在dateFormat属性,因此我们可以在配置文件中配置如下信息
spring.mvc.date-format=yyyy-mm-dd
此处列出的所有值都在WebMvcProperties中存在对应的属性,并且已经有默认值了
可以看到在向容器中注入时就会使用我们配置好的值了,其他没有配置的属性则是使用默认值
4.总结
简单概况下自动配置原理:
- 读取spring-autoconfigure-metadata.properties获取所有自动配置类
- 根据是否引入对应的starter判断自动配置类是否生效
- 每个自动配置类对应一个或多个Properties类,其中该类中存在使用starter时需要的所有默认配置
- 我们可以在配置文件中覆盖掉默认值
因此SpringBoot的自动配置原理是它在内部帮我们写好了所有可能要用到的配置项,当满足一定条件后就加载对应的配置类,因此我们可以开箱即用,如果它提供的功能还不能满足你的需求,你还可以自定义starter