前言
SpringBoot帮我们把一切都做好了,让我们只关注业务逻辑的开发,让我们对原理一探究竟。
@SpringBootApplication注解
Spring的一切自动配置起源于主程序的SpringBootApplication注解,进入SpringBootApplication注解可以看到, 他是由三个注解组合而成的。
-
@SpringBootConfiguration
-
@EnableAutoConfiguration
-
@ComponentScan
@SpringBootConfiguration
用@Configuration注解标注, 就表示SpringBootConfiguration是一个配置类(Springboot的核心配置类),就说明了我们创建的Springboot应用的主程序类也是一个配置类,
@ComponentScan
指定包的扫描,腰扫描那些包。
@EnableAutoConfiguration (核心重点)
由两个个注解组合而成
@AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class})
@AutoConfigurationPackage
进入@AutoConfigurationPackage 可以看到这个类上面标注了一个@Import({Registrar.class}) 注解, 表示给容器导入一个组件
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
我们进入@Import({Registrar.class})的Registrar.class类看一下,到底要导入什么组件。
- 利用Registrar给容器中导入一系列组件
- 将指定的一个包下的所有组件导入进来?MainApplication 所在包下。
Registrar类中有两个方法, 第一个方法就是批量注册组建的,这里的参数metadata就是标注该注解的类,最终也就是我们创建的SpringBoot应用程序的主程序启动类。
AutoConfigurationPackages.register方法中参数
(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]) 利用标注在主程序的类的元数据计算机出主程序所在的包名,创建一个数组然后注册到容器,这也就说明了为什么我们创建的Controller等要在主类包的下面。(register就是把某一个包下的所有组件批量注册进去)
@Import({AutoConfigurationImportSelector.class})
给容器中批量导入组件,导入那些组件呢?
进入AutoConfigurationImportSelector.class, 有一个selectImports方法,返回一个数组,返回哪些就是给容器中导入哪些组件。
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
selectImports方法中有一个getAutoConfigurationEntry方法, 所有的东西都是通过这个方法得到的,然后再autoConfigurationEntry.getConfigurations()得到配置返回。
我们看一下getAutoConfigurationEntry源码,List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); 活得了134个类,这是全部要导入到容器里面的。
我们再继续往下看,看看List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes) 是如何获取这134个组建的呢?一直从方法里面往下调,一直到SpringFactoriesLoader的loadSpringFactories方法。
从META-INF/spring.factories位置来加载一个文件。 默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件 spring-boot-autoconfigure-2.3.4.RELEASE.jar(这是核心自动配置类)包里面也有META-INF/spring.factories
文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
自动配置:
只有我们在pom.xml文件中引入了的组件才会生效, 因为每个XXXautoConfigure是通过@ 注解进行条件装配的,如果我们在pom.xml文件中引入了相关依赖,那么这个依赖jar就会生效,通过@ConditionalOnBean({CacheAspectSupport.class})条件的判断来决定是否注入Bean,下图,如果容器中没有CacheManager,那么整个类里面的方法就不执行了,如果存在那么就注入。
Web自动配置
-
DispatcherServletRegistrationConfiguration
全流程原理:主类上的@SpringBootApplication注解上的@EnableAutoConfiguration注解。
通过@EnableAutoConfiguration上的@Import({AutoConfigurationImportSelector.class})
AutoConfigurationImportSelector中的selectImports方法一直往里调用,从META-INF/spring.factories位置来加载一个文件。 默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件 spring-boot-autoconfigure-2.3.4.RELEASE.jar(这是核心自动配置类)包里面也有META-INF/spring.factories, 加载134个组件。再通过pom.xml文件中的导入的依赖场景按需加载。(其他如字符解析器,视图解析器都是这样注入的)
因为默认导入了spring-boot-starter-web场景, 那么web/servlet的依赖都会被导入DispatcherServletRegistrationConfiguration就是SpringMVC的前端控制器的自动配置。
WebMvcProperties的属性通过配置文件设置给dispatcherServlet实例
@EnableConfigurationProperties({WebMvcProperties.class})这个注解主要用来把配置文件的值绑定到WebMvcProperties这个类上并注入到容器
SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先
- 底层配置的原理就是通过@ConditionalOnBean({XXX.class})条件的判断来决定是否注入Bean,注入的,如果我们要自定义配置,可以按照这种方式
@Bean
@ConditionalOnMissingBean({MultipartConfigElement.class, CommonsMultipartResolver.class})
public MultipartConfigElement multipartConfigElement() {
return this.multipartProperties.createMultipartConfig();
}
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
}
总结:
- SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
- 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
- 生效的配置类就会给容器中装配很多组件
- 只要容器中有这些组件,相当于这些功能就有了
- 定制化配置
用户直接自己@Bean替换底层的组件
用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration ---> 组件 ---> xxxxProperties里面拿值 ----> application.properties