浅看SpringBoot的自动装配

系列文章目录

SpringBoot启动的时候做了什么(1)
SpringBoot启动的时候做了什么(2)



前言

SpringBoot的自动配置是一个很重要的特点,它可以大量的减少我们对相关框架的配置工作。之前两篇文章讲了SpringBoot的main方法内部逻辑,接下来开始学习SpringBoot的自动配置。


正文

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration  //标明该类为配置类
@EnableAutoConfiguration  //启动自动装配功能
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

@SpringBootApplication注解是个组合注解,其上有三个关键注解:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan

@SpringBootConfiguration 其实就是被Spring的@Configuration修饰的,两者功能一致,只是在SpringBoot中换了个名字而已。

1:@EnableAutoConfiguration

@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 {};
}

1.1:@AutoConfigurationPackage

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

可以看到,要分析@AutoConfigurationPackage 的作用,关键入口是AutoConfigurationPackages.Registrar.class

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));
	}

}

RegistrarAutoConfigurationPackages的一个静态内部类,再看register方法:

private static final String BEAN = AutoConfigurationPackages.class.getName();
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
	//BEAN 就是当前类,项目启动后第一次解析,肯定不会进第一个if分支
	if (registry.containsBeanDefinition(BEAN)) {
		BasePackagesBeanDefinition beanDefinition = (BasePackagesBeanDefinition) registry.getBeanDefinition(BEAN);
		beanDefinition.addBasePackages(packageNames);
	}
	else {
		registry.registerBeanDefinition(BEAN, new BasePackagesBeanDefinition(packageNames));
	}
}

BEAN 就是当前类,项目启动后第一次解析,肯定不会进第一个if分支。
第二个分支里边的逻辑就很简单了,就是注册一个BeanDefinition
关于register方法的第一个参数BeanDefinitionRegistry之前写过文章,点我。⬅️👀
回到调用register的地方🔙🔙🔙

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
	register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}

那接下来其实我们只要搞清楚register的第二个参数,就可以明白AutoConfigurationPackage做了什么。
别闹了,不会还要看代码吧,直接debug不来的痛快么😂
在这里插入图片描述
debug结果可以看到new PackageImports(metadata).getPackageNames()其实就是获取本项目启动类所在的项目路径。
在这里插入图片描述
beanDefinitionMap中也看到了当前启动类项目路径已被注册。

总结
@AutoConfigurationPackage作用是将启动类所在路径注册到Spring。

1.2:@Import(AutoConfigurationImportSelector.class)

这里需要知道@Import是做什么的,此注解不做展开。

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
	if (!isEnabled(annotationMetadata)) {
		return NO_IMPORTS;
	}
	AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
	return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

!isEnabled(annotationMetadata):判断当前项目是否开启自动装配,是通过一个配置实现的,默认打开。很简单就贴代码了。
重点看getAutoConfigurationEntry(annotationMetadata)

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);
}
1.2.1:getAttributes(annotationMetadata)

@EnableAutoConfiguration有两个属性:

Class<?>[] exclude() default {};
String[] excludeName() default {};

getAttributes(annotationMetadata)这个方法的作用就是获取这两个属性的值。

1.2.2:getCandidateConfigurations(annotationMetadata, attributes)
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
	List<String> configurations = new ArrayList<>(
			SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
	ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
	Assert.notEmpty(configurations,
			"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
					+ "are using a custom packaging, make sure that file is correct.");
	return configurations;
}

先看SpringFactoriesLoader.loadFactoryNames
在这里插入图片描述
在这里插入图片描述
可以看到这里就是从META-INF/spring.factories中获取所有的EnableAutoConfiguration实现。

再看ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
在这里插入图片描述
这个方法就是从spring-boot-autoconfigure中获取springboot目前支持的各框架的配置类。
简单看几个:
在这里插入图片描述
后边的就没啥必要看了,就是做一下去重、剔除之前exclued配置的。

2:@ComponentScan

这个下篇再说吧,要下班了


总结

META-INF/spring.factories中获取所有配置类,中间用到了SPI机制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高级摸鱼工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值