携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情
约定大于配置原理
结论:
SpringBoot给我们提供了大量自动配置类. 从而让我们能快速启动一个web项目.
那么在底层, 加载自动配置类的入口是什么? --就是SpringBoot的启动类
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
启动类中有一个`@SpringBootApplication注解, 在main方法中调用静态方法SpringAllication.run(), 传入了该类, 从而能获得该类的注解@SpringBootApplication, 该注解中其实包含了很多底层注解, 如
@EnableAutoConfiguration, 表示允许自动配置,- 还有
@ComponentScan, 用来进行扫描包的配置
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
//内容不看了
}
而@EnableAutoConfiguration注解中, 有一个@Import注解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
会将注解中对应的类注册为Spring中的组件, 而如果该class实现了ImportSelector接口的话, 会去找该接口中的selectImports()方法的返回值, 是一个String数组, 表示众多类的全限定类名.
// DeferredImportSelector是ImportSelector的子类
public class AutoConfigurationImportSelector implements DeferredImportSelector {
// ...
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
//...
}
这个方法的功能是可以通过注解@EnableAutoConfiguration, 可以一次性加载很多Spring预设的组件.
该方法会加载配置文件, 读取里面的值, 然后加载为String数组, 它加载哪里的配置文件呢?
- 原先的版本加载autoconfigure依赖下的
/META-INF/spring.factories文件中, 保存了很多键值对, key是EnableAutoConfiguration的全限定类名, value是String[]数组, 通过逗号来分割众多元素 - 现在的版本产生了一点变化, 还是在autoconfigure依赖下
/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件, 包含的是spring提供的自动配置类的全限定类名. - 当然之前位置autoconfigure依赖下的
/META-INF/spring.factories里的配置还是会读取的, 而新位置的是更多的补充.
下面调用了getAutoConfigurationEntry()方法加载数组, 87行加载为一个list, 然后转换为一个String数组, 其中的getCandateConfigurations()中, 有一行文件名, 会加载指定目录下的配置文件, 并读取其中的值.
这就是自动配置类是如何被加载的.
这些自动配置类里有一些注解
@ConditionalOnXXX当满足xxx条件时, 其他的注解会生效
@ConditionalOnMissingXXX当满足没有xxx条件时, 其他的注解会生效
这两类注解会和其他注解一起使用, 并决定这其他注解是否生效