SpringBoot⾃动配置原理
1.什么是⾃动配置
个⼈理解SpringBoot的⾃动配置就是在系统启动的过程中⾃动扫描加载starter和⾃定义的配置类和配置⽂件中的bean,并且能根据当前环境和条件动态加载bean,达到开箱即⽤的⽬的。
2.从注解反向看⾃动配置
说到⾃动配置,很多帖⼦会直接从启动类的main函数说起,从@SpringBootApplication这个⼊⼿,进⽽找到加载Bean的⼊⼝,⼀般情况下是可以这样看的。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, class = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, class =雪菊功效
AutoConfigurationExcludeFilter.class) })
public @interface寒假日记500字
SpringBootApplication {
SpringBootApplication 这个注解是个复合注解,
@SpringBootConfiguration 这个注解的作⽤和@Configuration的作⽤是⼀致的,声明当前类为⼀个配置类。
@ComponentScan 这个注解的作⽤是声明Bean扫描的相关信息,扫描路径和排除,包含关系
@EnableAutoConfiguration 字⾯意思是开启⾃动配置。它本⾝也是⼀个复合注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
@AutoConfigurationPackage注解其实是向容器导⼊了⼀个Bean,
@Import(AutoConfigurationImportSelector.class)向容器导⼊了AutoConfigurationImportSelector 这个Bean,这个Bean的作⽤是加载⾃动配置类
public String[] lectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
//加载⾃动配置类
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
Configurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntr高原红歌词
y(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//获取候选的配置类名称,其实是加载包路径下的META-INF/spring.factories 中的类路径
List<St目前最赚钱的行业
ring> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//排重
configuration简单协议书
s = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClass(configurations, exclusions);
//移除要排除的配置类
/
/筛选满⾜条件的配置类,这个地⽅其实是根据Condition过滤到满⾜条件的配置类
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
到此为⽌,我们仅仅能看到加载了哪些类,但是每个类中⼜有很多Bean,每个Bean上⼜加了很多Condition注解,那这些Bean是如何加载的?这个AutoConfigurationImportSelector是什么时候被触发的?如果单从注解反向看的话是很难回答的?
3.从启动流程正向看⾃动配置
要想真正了解⾃动配置原理,还是要从启动流程中下⼿,启动过程中有很重要的⼀步是
refreshContext(context);
它调⽤的是AbstractApplicationContext的 refresh⽅法,启动有⼀步是执⾏BeanFactory的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
这⾥⾯有⼀段执⾏ BeanDefinitionRegistryPostProcessor 的代码,这个是和bean注册相关的
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// 这个地⽅拿到的是t.annotation.internalConfigurationAnnotationProcessor 这个类,
String[] postProcessorNames =
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.Bean(ppName, BeanDefinitionRegistryPostProcessor.class));
procesdBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
征信中国
//currentRegistryProcessors中存放的是ConfigurationClassPostProcessor,这个类是⾃动配置的核⼼
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
invoke ⽅法调⽤的t.annotation.ConfigurationClassPostProcessor的processConfigBeanDefinitions⽅法
String[] candidateNames = BeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = BeanDefinition(beanName);
if (Attribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been procesd as a configuration class: " + beanDef);
}
}
el if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, t快速记忆英语
adataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
从候选bean中选取有@Configuration的类,候选的有下⾯⼏个,其中只有我们⾃⼰的主启动类包含了这个注解
t.annotation.internalConfigurationAnnotationProcessor
t.annotation.internalAutowiredAnnotationProcessor
t.annotation.internalCommonAnnotationProcessor
t.event.internalEventListenerProcessor
t.event.internalEventListenerFactory
conditionTestApplication(主启动类)
org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory
接下来执⾏parr,这⾥⾯循环调⽤,将所有@Configuration的配置类都处理了⼀遍,将使⽤@Bean注解的⽅法都提取出来了ConfigurationClassParr parr = new ConfigurationClassParr(
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyPard = new HashSet<>(configCandidates.size());
do {
//记载配置类
parr.par(candidates);
parr.validate();
//存放配置类及Bean信息
Set<ConfigurationClass> configClass = new LinkedHashSet<>(ConfigurationClass());
// Read the model and create bean definitions bad on its content
if (ader == null) {
registry, this.sourceExtractor, sourceLoader, vironment,
this.importBeanNameGenerator, ImportRegistry());
}
//根据条件注解,加载Bean
alreadyPard.addAll(configClass);
parr.par(candidates); ⽅法中调⽤了 this.deferredImportSelectorHandler.process(),⽽ AutoConfigurationImportSelector 是 DeferredImportSelector的实现类
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
deferredImports.forEa吃的英语单词
ch(handler::register);
//进⾏导⼊
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : upings.values()) {
ConfigurationClass configurationClass = (
try {
processImports(configurationClass, asSourceClass(configurationClass),
ImportClassName()), fal);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
}
});
}
}
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
}
up.lectImports();
}
group.process的调⽤了AutoConfigurationImportSelector.process ⽅法,这样就和前⾯的从注解看实现的步骤对上了,加载配置类的⼊⼝就找到了,并且经过⼀层过滤public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Asrt.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
SimpleName(),
// 这个地⽅就是执⾏的导⼊配置类
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.
getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : Configurations()) {
}
}
再回到processGroupImports() 这个⽅法很复杂,作⽤是循环调⽤所有配置类,将⾃动配置类中的有 @ComponentScan
@Import @ImportResource 这些注解的类都找到,如果没有注解作为配置类使⽤,并且将结果存在在configClass中,这个类中存放的是所有配置类及配置类中产⽣Bean⽅法的信息,后⾯将通过这些信息确定要最终加载哪些Bean。
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
// 判断类是不是要跳过
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = BeanName();
if (StringUtils.hasLength(beanName) && ainsBeanDefinition(beanName)) {
}
Metadata().getClassName());
return;
}
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// 将configerClass 转成BeanDefinition并注册到BeanFactory
for (BeanMethod beanMethod : BeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
ImportedResources());
ImportBeanDefinitionRegistrars());
}
ConditionEvaluator.shouldSkip 的作⽤就是根据判断Condition注解能否⽣效
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPha pha) { if (metadata == null || !metadata.isAnnotated(Name())) {
return fal;
}
if (pha == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPha.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPha.REGISTER_BEAN);
}
List<Condition> conditions = new ArrayList<>();
for (String[] conditionClass : getConditionClass(metadata)) {
for (String conditionClass : conditionClass) {
Condition condition = getCondition(conditionClass, ClassLoader());
conditions.add(condition);
}
}
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPha requiredPha = null;
if (condition instanceof ConfigurationCondition) {
requiredPha = ((ConfigurationCondition) condition).getConfigurationPha();
}
if ((requiredPha == null || requiredPha == pha) && !condition.t, metadata)) {
return true;
}
}
return fal;
}
这样整个⾃动配置的链路就串起来了,加载⾃动配类,使⽤条件注解判断哪些Bean需要加载到容器中都可以找到实现。