SpringBoot自动配置原理
1.自动配置原理
使用SpringBoot之后,一个整合了SpringMVC的WEB工程开发,变的无比简单,那些繁杂的配置都消失不见了,这是如何做到的?
一切魔力的开始,都是从我们的main函数来的,所以我们再次来看下启动类:
我们发现特别的地方有两个:
- 注解:@SpringBootApplication
- run方法:SpringApplication.run()
我们分别来研究这两个部分。
2.了解@SpringBootApplication
点击进入,查看源码:
这里重点的注解有3个:
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
2.1.@SpringBootConfiguration
我们继续点击查看源码:
通过这段我们可以看出,在这个注解上面,又有一个@Configuration
注解。通过上面的注释阅读我们知道:这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了@Configuration
的类,并且读取其中的配置信息。而@SpringBootConfiguration
是来声明当前类是SpringBoot应用的配置类,项目中只能有一个。所以一般我们无需自己添加。
2.2.@EnableAutoConfiguration
关于这个注解,官网上有一段说明:
The second class-level annotation is
@EnableAutoConfiguration
. This annotation
tells Spring Boot to “guess” how you want to configure Spring, based on the jar
dependencies that you have added. Sincespring-boot-starter-web
added Tomcat
and Spring MVC, the auto-configuration assumes that you are developing a web
application and sets up Spring accordingly.
简单翻译以下:
第二级的注解
@EnableAutoConfiguration
,告诉SpringBoot基于你所添加的依赖,去“猜测”你想要如何配置Spring。比如我们引入了spring-boot-starter-web
,而这个启动器中帮我们添加了tomcat
、SpringMVC
的依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了!
总结,SpringBoot内部对大量的第三方库或Spring内部库进行了默认配置,这些配置是否生效,取决于我们是否引入了对应库所需的依赖,如果有那么默认配置就会生效。
所以,我们使用SpringBoot构建一个项目,只需要引入所需框架的依赖,配置就可以交给SpringBoot处理了。除非你不希望使用SpringBoot的默认配置,它也提供了自定义配置的入口。
2.2.1.@ComponentScan
我们跟进源码:
并没有看到什么特殊的地方。我们查看注释:
大概的意思:
配置组件扫描的指令。提供了类似与
标签的作用
通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包
而我们的@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。因此,一般启动类会放在一个比较前的包目录中。
3.默认配置原理
3.1默认配置类
通过刚才的学习,我们知道@EnableAutoConfiguration会开启SpringBoot的自动配置,并且根据你引入的依赖来生效对应的默认配置。那么问题来了:
- 这些默认配置是在哪里定义的呢?
- 为何依赖引入就会触发配置呢?
其实在我们的项目中,已经引入了一个依赖:spring-boot-autoconfigure,其中定义了大量自动配置类:
还有:
非常多,几乎涵盖了现在主流的开源框架,例如:
- redis
- jms
- amqp
- jdbc
- jackson
- mongodb
- jpa
- solr
- elasticsearch
... 等等
我们来看一个我们熟悉的,例如SpringMVC,查看mvc 的自动配置类:
打开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):
还有很多,这里就不一一截图了。
3.2.默认配置属性
另外,这些默认配置的属性来自哪里呢?
我们看到,这里通过@EnableAutoConfiguration注解引入了两个属性:WebMvcProperties和ResourceProperties。这不正是SpringBoot的属性注入玩法嘛。
我们查看这两个属性类:
找到了内部资源视图解析器的prefix和suffix属性。
ResourceProperties中主要定义了静态资源(.js,.html,.css等)的路径:
如果我们要覆盖这些默认属性,只需要在application.properties中定义与其前缀prefix和字段名一致的属性即可。
4.总结
SpringBoot为我们提供了默认配置,而默认配置生效的条件一般有两个:
- 你引入了相关依赖
- 你自己没有配置
1)启动器
所以,我们如果不想配置,只需要引入依赖即可,而依赖版本我们也不用操心,因为只要引入了SpringBoot提供的stater(启动器),就会自动管理依赖及版本了。
因此,玩SpringBoot的第一件事情,就是找启动器,SpringBoot提供了大量的默认启动器,参考课前资料中提供的《SpringBoot启动器.txt》
2)全局配置
另外,SpringBoot的默认配置,都会读取默认属性,而这些属性可以通过自定义application.properties
文件来进行覆盖。这样虽然使用的还是默认配置,但是配置中的值改成了我们自定义的。
因此,玩SpringBoot的第二件事情,就是通过application.properties
来覆盖默认属性值,形成自定义配置。