Spring自动配置执行流程
要说SpringBoot自动配置,我们要先了解SpringBoot的Bean加载流程。
SpringBoot的Main方法中执行SpringApplication.run(EureakServerApplication.class, args)进行启动。
在在启动进程中执行了SpringApplication.refresh()方法,该方法来自父类AbstractApplicationContext。
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext)applicationContext).refresh();
}
我们进一步看AbstractApplicationContext的refresh方法。看源码,哇哇,英文注释很全的。棒棒哒。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//Spring Bean初始化加载并注册到Spring容器中
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();// 用户定义Bean加载
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
… …
}
}
在invokeBeanFactoryPostProcessors(beanFactory) 里通过ConfigurationClassPostProcessor配置类处理器processConfigBeanDefinitions()方法加载并初始化配置信息。到这里我们终于找见自动配置的执行入口了,哈哈。加油,继续往下看。这里有个注释,翻译成人话:解析每一个带有@Configuration注解的类
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(…);
parser.parse(candidates);
配置解析处理完成后,对解析结果进行处理。processDeferredImportSelectors()//处理延迟导入选择器
for (DeferredImportSelectorGrouping grouping : groupings.values()) {
grouping.getImports().forEach(entry -> {
};
感觉有点眼熟, grouping.getImports() 导入呀,延迟导入选择器。恩靠谱,我们进getImports()看看。
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
return this.group.selectImports();
}
this.group.process(……参数暂时先不看了); process是处理什么的?恩,进去,哦买糕的,竟然是DeferredImportSelector。这个熟悉吗,简直太熟悉了。
public interface DeferredImportSelector extends ImportSelector {
/**
* Return a specific import group or {@code null} if no grouping is required.
* @return the import group class or {@code null}
*/
@Nullable
default Class<? extends Group> getImportGroup() {
return null;
}
/**
* Interface used to group results from different import selectors.
*/
interface Group {
/**
* Process the {@link AnnotationMetadata} of the importing @{@link Configuration}
* class using the specified {@link DeferredImportSelector}.
*/
void process(AnnotationMetadata metadata, DeferredImportSelector selector);
/**
* Return the {@link Entry entries} of which class(es) should be imported for this
* group.
*/
Iterable<Entry> selectImports();
到这里,我们返回来看,我们当前的目标是什么,SpringBoot自动配置。
启动类注解@SpringBootApplication,开启了自动配置属性。
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication
自动配置开启注解@EnableAutoConfiguration, 导入自动配置选择器
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration
咣咣咣,我们再来看看AutoConfigurationImportSelector自动配置选择器,AutoConfigurationImportSelector实现了DeferredImportSelector接口。
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered
那么上面的DeferredImportSelector.process(AnnotationMetadata metadata, DeferredImportSelector selector)方法到底执行了什么?
我们进入AutoConfigurationImportSelector.process()的世界看一看。
@Override
public void process(AnnotationMetadata annotationMetadata,
DeferredImportSelector deferredImportSelector) {
String[] imports = deferredImportSelector.selectImports(annotationMetadata);
for (String importClassName : imports) {
this.entries.put(importClassName, annotationMetadata);
}
}
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
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 = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
/**
* Return the auto-configuration class names that should be considered. By default
* this method will load candidates using {@link SpringFactoriesLoader} with
* {@link #getSpringFactoriesLoaderFactoryClass()}.
* @param metadata the source metadata
* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
* attributes}
* @return a list of candidate configurations
*/
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;
}
总结
SpringBoot通过EnableAutoConfigurationImportSelector的导入的配置功能,将所有符合条件的@Configuration配置都加载到当前的IoC容器。
AutoConfigurationImportSelector中的方法getCandidateConfigurations,得到待配置的class的类名集合,这个集合就是所有需要进行自动配置的类,而是否配置的关键在于META-INF/spring.factories文件中是否存在该配置信息。
打开,如下图可以看到所有需要配置的类全路径都在文件中,每行一个配置,多个类名逗号分隔,而\表示忽略换行
SpringBoot自动化配置关键组件关系图