SpringBoot自动配置的加载流程及实现原理

Spring自动配置执行流程

要说SpringBoot自动配置,我们要先了解SpringBoot的Bean加载流程。

SpringBootMain方法中执行SpringApplication.run(EureakServerApplication.class, args)进行启动。

在在启动进程中执行了SpringApplication.refresh()方法,该方法来自父类AbstractApplicationContext

protected void refresh(ApplicationContext applicationContext) {
    Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
    ((AbstractApplicationContext)applicationContext).refresh();
}

我们进一步看AbstractApplicationContextrefresh方法。看源码,哇哇,英文注释很全的。棒棒哒。

@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自动化配置关键组件关系图

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页