05 自动配置原理
目标:了解Spring Boot项目的配置加载流程
小结:
- 在
META-INF\spring.fatories
文件中定义了很多自动配置类;可以根据在pom.xml文件中添加的 启动器依赖自动配置组件 - 通过如下流程可以去修改application配置文件,改变自动配置的组件默认参数
1.了解@SpringBootApplication
源码:
这里重点的注解有3个:
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
1.1 @SpringBootConfiguration
源码:
)]
通过这段我们可以看出,在这个注解上面,又有一个 @Configuration 注解。通过上面的注释阅读我们知道:这个注 解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了 @Configuration 的类,并且读取其中的配 置信息。而 @SpringBootConfiguration 是来声明当前类是SpringBoot应用的配置类,项目中只能有一个。所以一 般我们无需自己添加。
1.2.@EnableAutoConfiguration
第二级的注解 @EnableAutoConfiguration ,告诉Spring Boot基于你所添加的依赖,去“猜测”你想要如何配 置Spring。比如我们引入了 spring-boot-starter-web ,而这个启动器中帮我们添加了 tomcat 、 SpringMVC 的依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了!
总结,Spring Boot内部对大量的第三方库或Spring内部库进行了默认配置,这些配置是否生效,取决于我们是否引 入了对应库所需的依赖,如果有那么默认配置就会生效。
所以,我们使用SpringBoot构建一个项目,只需要引入所需框架的依赖,配置就可以交给SpringBoot处理了。除非 你不希望使用SpringBoot的默认配置,它也提供了自定义配置的入口。
1.3 @ComponentScan
源码:
配置组件扫描的指令。提供了类似与 context:component-scan 标签的作用
通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明 这个注解的类所在的包开始,扫描包及子包。
而我们的@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子 包。因此,一般启动类会放在一个比较前的包目录中
2.默认配置原理
2.1. spring.factories
在SpringApplication类构建的时候,有这样一段初始化代码:
进入源码:
这里发现会通过loadFactoryNames尝试加载一些FactoryName,然后利用createSpringFactoriesInstances将这些 加载到的类名进行实例化。
继续跟进loadFactoryNames方法:
发现此处会利用类加载器加载某个文件: FACTORIES_RESOURCE_LOCATION ,然后解析其内容。我们找到这个变量的 声明:
可以发现,其地址是: META-INF/spring.factories ,我们知道,ClassLoader默认是从classpath下读取文件,因 此,SpringBoot会在初始化的时候,加载所有classpath:META-INF/spring.factories文件,包括jar包当中的。 而在Spring的一个依赖包:spring-boot-autoconfigure中,就有这样的文件:
以后我们引入的任何第三方启动器,只要实现自动配置,也都会有类似文件。
2.2 默认配置类
我们打开刚才的spring.factories文件:
可以发现以EnableAutoConfiguration接口为key的一系列配置,key所对应的值,就是所有的自动配置类,可以在当 前的jar包中找到这些自动配置类:
非常多,几乎涵盖了现在主流的开源框架,例如:
redis jms amqp jdbc jackson mongodb jpa solr elasticsearch
打开WebMvcAutoConfiguration:
我们看到这个类上的4个注解:
- @Configuration :声明这个类是一个配置类
- @ConditionalOnWebApplication(type = Type.SERVLET) ConditionalOn,翻译就是在某个条件下,此处就是满足项目的类是是Type.SERVLET类型,也就是一个普通 web工程,显然我们就是
- @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) 这里的条件是OnClass,也就是满足以下类存在:Servlet、DispatcherServlet、WebMvcConfigurer,其中 Servlet只要引入了tomcat依赖自然会有,后两个需要引入SpringMVC才会有。这里就是判断你是否引入了相关 依赖,引入依赖后该条件成立,当前类的配置才会生效!
- @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) 这个条件与上面不同,OnMissingBean,是说环境中没有指定的Bean这个才生效。其实这就是自定义配置的入 口,也就是说,如果我们自己配置了一个WebMVCConfigurationSupport的类,那么这个默认配置就会失效!
接着,我们查看该类中定义了什么:
视图解析器:
处理器适配器(HandlerAdapter):
还有很多,这里就不一一截图了。
2.3 默认配置属性
另外,这些默认配置的属性来自哪里呢?
我们看到,这里通过@EnableAutoConfiguration注解引入了两个属性:WebMvcProperties和 ResourceProperties。这不正是SpringBoot的属性注入玩法嘛。
我们查看这两个属性类:
找到了内部资源视图解析器的prefix和suffix属性。
ResourceProperties中主要定义了静态资源(.js,.html,.css等)的路径:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191230233944152.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ3MzYwODI=,size_16,color_FFFFFF,t_70
如果我们要覆盖这些默认属性,只需要在application.properties中定义与其前缀prefix和字段名一致的属性即可。
3.总结
SpringBoot为我们提供了默认配置,而默认配置生效的步骤:
- @EnableAutoConfiguration注解会去寻找 META-INF/spring.factories 文件,读取其中以 EnableAutoConfiguration 为key的所有类的名称,这些类就是提前写好的自动配置类
- 这些类都声明了 @Configuration 注解,并且通过 @Bean 注解提前配置了我们所需要的一切实例
- 但是,这些配置不一定生效,因为有 @ConditionalOn 注解,满足一定条件才会生效。比如条件之一:是一些 相关的类要存在
- 类要存在,我们只需要引入了相关依赖(启动器),依赖有了条件成立,自动配置生效。
- 如果我们自己配置了相关Bean,那么会覆盖默认的自动配置的Bean
- 我们还可以通过配置application.yml文件,来覆盖自动配置中的属性
1)启动器
所以,我们如果不想配置,只需要引入依赖即可,而依赖版本我们也不用操心,因为只要引入了SpringBoot提供的 stater(启动器),就会自动管理依赖及版本了。 因此,玩SpringBoot的第一件事情,就是找启动器,SpringBoot提供了大量的默认启动器
2)全局配置
另外,SpringBoot的默认配置,都会读取默认属性,而这些属性可以通过自定义 application.properties 文件来 进行覆盖。这样虽然使用的还是默认配置,但是配置中的值改成了我们自定义的。
启动器,SpringBoot提供了大量的默认启动器
2)全局配置
另外,SpringBoot的默认配置,都会读取默认属性,而这些属性可以通过自定义 application.properties 文件来 进行覆盖。这样虽然使用的还是默认配置,但是配置中的值改成了我们自定义的。
因此,玩SpringBoot的第二件事情,就是通过 application.properties 来覆盖默认属性值,形成自定义配置。我 们需要知道SpringBoot的默认属性key,非常多,可以再idea中自动提示