介绍:springboot的自动装配原理,从启动类上的注解来解释
@SpringBootApplication
@SpringBootApplication详解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
可以看见这是一个合成注解,我们挨个分析每个注解的作用
@SpringBootConfiguration
@Documented
@Configuration
public @interface SpringBootConfiguration {
@Configuration代表了这是一个配置类,也就是我们的mian程序也是一个配置类
@ComponentScan
这个注解是用来包扫描的
@EnableAutoConfiguration
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
可以看见这是两个注解的合成注解
@AutoConfigurationPackage
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
自动配置包,可以看见它使用了@Import 这个注解,这是给容器导入一个组件。我们点进入这个Registrar
类
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}
}
Registrar
类的作用是给容器中导入一系列组件。
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry)
AnnotationMetadata
代表注解的元信息,也就是得到@AutoConfigurationPackage
注解的元信息。但这个注解实际的作用类是我们的启动类上面,如下图
然后在此方法中,得到我们的主启动类所在的包名,并注册到一个数组中
PackageImports(metadata).getPackageNames().toArray(new String[0])
所以@AutoConfigurationPackage是把主启动类所在的包下的所有组件批量注册。这也是我们的默认的包扫描的规则
@Import(AutoConfigurationImportSelector.class)
我们进入AutoConfigurationImportSelector类的下面这个方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//我们进入这个方法,这个方法就是批量导入组件的方法
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//获取所有需要导入到容器中的配置类,我们进入这个方法。如下图
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//移除一些重复的
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
在下面这个方法中,利用工厂加载,得到所有的MEAT-INF/spring.factories的位置的其中的文件
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
比如说在spring-boot-autoconfigure这个jar包下面就有127个要导入的配置项,官方提供的127个场景就全包括在此。
但加载不是意味着生效,springboot可以做到按需开启。SpringBoot有一个注解@Conditional
,只有满足了@Conditional注解以及其子注解的要求,配置类才会生效