简单总结
SpringBoot自动配置主要是通过@EnableAutoConfiguation,@Conditional,@EnableConfigProperties,@ConfigurationProperties等注解实现的。
具体流程如下:当我们写好一个启动类后,我们会在启动类上加一个@SpringBootApplication,我们可以点开这个注解可以看到它内部有一个@EnableAutoConfiguation的注解,我们继续进入这个注解可以看到一个@Import的注解,这个注解引入了一个AutoConfigurationImportSelector的类。我们继续打开这个类可以看到它有一个selectorImport的方法,这个方法又调用了一个getCandidateConfigurations方法,这个方法内部通过SpringFactoriesLoader.loadFactoryNames最终调用loadSpringFactories加载到一个META-INF下的spring.factories文件。打开这个文件可以看到是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔。当我们通过springApplication.run启动的时候内部就会执行selectImports方法从而找到配置类对应的class。然后将所有自动配置类加载到Spring容器中,进而实现自动配置。
Spring Boot 自动配置原理
使用 Spring Boot 之后,做一个整合了 Spring MVC 的 Web 工程开发,变的无比简单,那些繁杂的配置都消失不见了,这是如何做到的?一切魔力的开始,都是从我们的 main 函数来的,所以我们再次来看下启动类:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
从上面代码我们发现特别的地方有两个:
- 注解:
@SpringBootApplication
; - run方法:SpringApplication.run()。
1、了解 @SpringBootApplication
点击进入,查看源码:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JbjobdU7-1640315963654)(图/1525488226710.png)]
这里重点的注解有3个:
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
1.1、@SpringBootConfiguration
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nFriLKNG-1640315963656)(图/1525488518514.png)]
通过这段我们可以看出,在这个注解上面,又有一个 @Configuration
注解。通过上面的注释阅读我们知道:这个注解的作用就是声明当前类是一个配置类,然后 Spring 会自动扫描到添加了 @Configuration
的类,并且读取其中的配置信息。而 @SpringBootConfiguration
是来声明当前类是 Spring Boot 应用的配置类,项目中只能有一个。所以一般我们无需自己添加。
1.2、@ComponentScan
我们的 @SpringBootApplication 注解声明的类就是 main 函数所在的启动类,因此扫描的包是该类所在包及其子包。因此,一般启动类会放在一个比较前的包目录中。
1.3、@EnableAutoConfiguration
@EnableAutoConfiguration
的作用,告诉 Spring Boot 基于你所添加的依赖,去“猜测”你想要如何配置 Spring。比如我们引入了 spring-boot-starter-web
,而这个启动器中帮我们添加了 tomcat
、SpringMVC
的依赖。此时自动配置就知道你是要开发一个 Web 应用,所以就帮你完成了 Web 及 Spring MVC 的默认配置了!
Spring Boot 内部对大量的第三方库或 Spring 内部库进行了默认配置,这些配置是否生效,取决于我们是否引入了对应库所需的依赖,如果有,那么默认配置就会生效。那么带来新的问题,如下:
- 这些默认配置是在哪里定义的呢?
- 为何依赖引入就会触发配置呢?
2、如何自动配置
@EnableAutoConfiguration
注解中导入了一个 AutoConfigurationImportSelector 配置类,该类中有个 getCandidateConfigurations 方法,方法的作用是委托 SpringFactoriesLoader 去读取 jar 包中的 META-INF/spring.factories 文件,并加载里面配置的自动配置对象,包括:AOP,PropertyPlaceholder,FreeMarker,HttpMessageConverter,Jackson,DataSourceDataSourceTransactionManager,DispatcherServlet 等等。
其实在我们的项目中,已经自动引入了一个依赖:spring-boot-autoconfigure,上面说到的这些自动配置类,都来自该包。
虽然 spring.factories 文件中定义了很多配置类,但并不是所有配置类都会生效,只有符合条件的是才会自动装配。
我们来看一个我们熟悉的,例如 Spring MVC,查看其自动配置类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HhYyv44U-1640315963656)(图/1525499859426.png)]
打开 WebMvcAutoConfiguration:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ohB28xb-1640315963657)(图/1525500000816.png)]
我们看到这个类上的 4 个注解:
-
@Configuration
:声明这个类是一个配置类 -
@ConditionalOnWebApplication(type = Type.SERVLET)
ConditionalOn,翻译就是在某个条件下,此处就是满足项目的类是是 Type.SERVLET 类型,我们现在的项目就满足了,就是一个 Web 工程。
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
这里的条件是 OnClass,也就是满足以下类存在:Servlet、DispatcherServlet、WebMvcConfigurer。这里就是判断你是否引入了 Spring MVC相关依赖,引入依赖后该条件成立,当前类的配置才会生效!
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
这个条件与上面不同,OnMissingBean,是说环境中没有指定的 bean 这个才生效。其实这就是自定义配置的入口,也就是说,如果我们自己配置了一个 WebMVCConfigurationSupport 的 bean,代表容器里已经存在该 bean 了,那么这个默认配置就会失效!
接着,我们查看 WebMvcAutoConfiguration 该类中定义了什么:
视图解析器:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zuqnurYU-1640315963658)(图/1525500405278.png)]
WebMvcAutoConfiguration 中使用了 @AutoConfigureAfter
注解,意为指定的类加载完了后,再加载本类。
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class })
而 DispatcherServletAutoConfiguration 中又做了很多事情,比如配置了前端控制器:
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
return dispatcherServlet;
}
3、总结
@SpringBootApplication
注解内部是3大注解功能的集成@ComponentScan
:开启组件扫描@SpringBootConfiguration
:作用等同于@Configuration
注解,也是用于标记配置类@EnableAutoConfiguration
:内部导入 AutoConfigurationImportSelector,该类中有个 getCandidateConfigurations 方法,读取 jar 包中 META-INF/spring.factories 文件中配置类,再根据条件进行加载和配置,比如:AOP,PropertyPlaceholder,FreeMarker,HttpMessageConverter,Jackson,DataSourceDataSourceTransactionManager,DispatcherServlet,WebMvc 等等
- SpringApplication.run(…)的作用
- 启动 Spring Boot 应用
- 加载自定义的配置类,完成自动配置功能
- 把当前项目配置到嵌入的 Tomcat 服务器
- 启动嵌入的 Tomcat 服务器