SpringBoot 自动配置原理学习总结

@SpringBootApplication:

这个注解标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot 需要运行这个类的main方法来启动SpringBoot应用。

//设置当前注解可以标记在哪
@Target({ElementType.TYPE})
//当注解标注的类编译以什么方式保留
@Retention(RetentionPolicy.RUNTIME)
//java doc 会生成注解信息
@Documented
//是否会被继承
@Inherited
//Spring Boot的配置类
@SpringBootConfiguration
//开启自动配置功能
@EnableAutoConfiguration
//扫描包
@ComponentScan(excludeFilters = {
	//TypeExcludeFilter:springboot对外提供的扩展类, 可以供我们去按照我们的方式进行排除
	@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}),
	//AutoConfigurationExcludeFilter:springboot对外提供的扩展类,可以供我们去按照我们的方式进行排除
	@Filter(type = FilterType.CUSTOM,classes ={AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
@EnableAutoConfiguration

告诉 SpringBoot开启自动配置,会帮我们自动去加载 自动配置类

@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 {};
}
自动配置原理:
  • Springboot通过@EnableAutoConfiguration注解来完成自动配置,注解内使用@import注解来完成导入配置的功能
  • @Import注解在AutoConfigurationImportSelector类实现了DeferredImportSelector,并且重写了getImportGroup的方法
  • getImportGroup返回了一个AutoConfigurationGroup实现类,实现了DeferredImportSelector.Group类,并重写了process和selectImports方法。
  • process方法会读取所有jar包中的Spring.factories文件并且过滤掉不需要的配置类,拿到过滤后的配置类List。这些文件中的类路径就是SpringBoot提前预置好的配置类。
  • selectImports方法对这些配置bean进行分组排序,分组就是把spring的bean和SpringBoot的bean区分开,目的是为了实现延迟加载。
  • @Import的DeferredImportSelector实现类在Spring中,加载到BeanDefinitionMap中的优先级是最低的,SpringBoot利用这个特性来实现延迟加载,延迟加载可以实现如果当前组中有和Spring中重复的bean定义,就不会再次加载,这样做的目的是为了能让我们自己实现自定义配置类。
  • 拿到所有的配置类后,会解析@ConditionalOnClass等一系列@Conditional条件注解,这个注解作用是当项目中存在某个类时才会使标有该注解的类或方法生效,比如说mybatisplus的配置类中,@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})表示存在SqlSessionFactory和SqlSessionFactoryBean这两个Class时配置类才生效。
  • 最后把过滤排序后的所有生效的配置类批量注册到BeanDefinitionMap中,实现自动配置。
  • 我们可以通过添加自定义的jar包和Spring.factories文件,实现自定义stater,并且重写selectImports方法实现自定义排序。
源码分析:

AutoConfigurationImportSelector类实现了DeferredImportSelector重写了getImportGroup方法对bean进行分组排序。

//实现了DeferredImportSelector
public class AutoConfigurationImportSelector implements DeferredImportSelector,
 BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
 	//分组排序
	@Override
	public Class<? extends Group> getImportGroup() {
		return AutoConfigurationGroup.class;
	}
}

getImportGroup返回了一个AutoConfigurationGroup内部类,AutoConfigurationGroup中实现了DeferredImportSelector.Group中的process方法,所以AutoConfigurationImportSelector中会调用process的重写。

private static class AutoConfigurationGroup implements DeferredImportSelector.Group,
			BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
	//重写DeferredImportSelector.Group中的process方法
	@Override
	public void process(AnnotationMetadata annotationMetadata,
			DeferredImportSelector deferredImportSelector) {
		Assert.state(
				deferredImportSelector instanceof AutoConfigurationImportSelector,
				() -> String.format("Only %s implementations are supported, got %s",
						AutoConfigurationImportSelector.class.getSimpleName(),
						deferredImportSelector.getClass().getName()));
		AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
				.getAutoConfigurationEntry(getAutoConfigurationMetadata(),
						annotationMetadata);
		this.autoConfigurationEntries.add(autoConfigurationEntry);
		for (String importClassName : autoConfigurationEntry.getConfigurations()) {
			this.entries.putIfAbsent(importClassName, annotationMetadata);
		}
	}
}

process会调用getAutoConfigurationEntry方法返回所有需要的自动配置类

protected AutoConfigurationEntry getAutoConfigurationEntry(
			AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		//获取@EnableAutoConfiguration中的exclude、excludeName等注解信息
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//读取“META-INF/spring.factories”文件中的所有自动配置类
		List<String> configurations = getCandidateConfigurations(annotationMetadata,
				attributes);
		//去除重复的配置项
		configurations = removeDuplicates(configurations);
		//根据@EnableAutoConfiguration中的exclude、excludeName获取不需要的配置类
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		// 根据:@EnableAutoConfiguration.exclude 
		// @EnableAutoConfiguration.excludeName 
		// spring.autoconfigure.exclude 进行排除
		checkExcludedClasses(configurations, exclusions);
		// exclusions 也排除
		configurations.removeAll(exclusions);
		// 通过读取spring.factories 中的OnBeanCondition\OnClassCondition\OnWebApplicationCondition进行过滤
		configurations = filter(configurations, autoConfigurationMetadata);
		//广播事件,最后根据多次过滤、判重,返回配置类合集
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
}

拿到需要的自动配置类后,就会调用selectImports中的sortAutoConfigurations方法,对当前组里的bean进行排序,让当前组里的配置类延迟加载。目的是为了保证先加载Spring中的bean定义,如果当前组中有和Spring中重复的bean定义,就不会再次加载了,目的是为了能让我们自己实现自定义配置类。

@Override
public Iterable<Entry> selectImports() {
	if (this.autoConfigurationEntries.isEmpty()) {
		return Collections.emptyList();
	}
	Set<String> allExclusions = this.autoConfigurationEntries.stream()
			.map(AutoConfigurationEntry::getExclusions)
			.flatMap(Collection::stream).collect(Collectors.toSet());
	Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
			.map(AutoConfigurationEntry::getConfigurations)
			.flatMap(Collection::stream)
			.collect(Collectors.toCollection(LinkedHashSet::new));
	processedConfigurations.removeAll(allExclusions);

	return sortAutoConfigurations(processedConfigurations,
			getAutoConfigurationMetadata())
					.stream()
					.map((importClassName) -> new Entry(
							this.entries.get(importClassName), importClassName))
					.collect(Collectors.toList());
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值