SpringBoot自动配置原理分析

继之前的文章SpringBoot核心注解之后,今天我们一起来分析一下SpringBoot的自动配置实现原理,表面上看起来深不可测,当我们分析过源码之后,会觉得它本身并没有那么复杂。

通过分析springboot源码,我们发现在@EnableAutoConfiguration注解中,@Import(Spring 提供的一个注解,可以导入配置类或者Bean到当前类中)导入了AutoConfigurationImportSelector类,根据名字来看,它应该就是我们要找到的目标了。

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

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}

进入上面这个类,我们可以找到选择自动配置的主入口:

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
	if (!isEnabled(annotationMetadata)) {
		return NO_IMPORTS;
	}
	AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
			.loadMetadata(this.beanClassLoader);
	AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
			autoConfigurationMetadata, annotationMetadata);
	return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

它调用了其他的几个方法来加载元数据等信息,最后返回一个包含许多自动配置类信息的字符串数组。

protected AutoConfigurationEntry getAutoConfigurationEntry(
			AutoConfigurationMetadata autoConfigurationMetadata,
			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 = filter(configurations, autoConfigurationMetadata);
	fireAutoConfigurationImportEvents(configurations, exclusions);
	return new AutoConfigurationEntry(configurations, exclusions);
}

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

这是的重点是:方法getCandidateConfigurations()返回了自动配置类的信息列表,而它通过调用SpringFactoriesLoader.loadFactoryNames()来扫描加载含有META-INF/spring.factories文件的jar包,该文件记录了具有哪些自动配置类。

接下来我们看看springboot中自动配置类的相关内容,我们选择一个具体的实践来看一下:

@Configuration
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({FeignClientProperties.class, FeignHttpClientProperties.class})
public class FeignAutoConfiguration {
    //....省略
}

我们可以看到对应的类的定义,其中@ConditionalOnClass注解是重点,该注解是@Conditional注解的一种。什么是@Conditional呢?

@Conditional是由Spring 4提供的一个新特性,用于根据特定条件来控制Bean的创建行为。而在我们开发基于Spring的应用的时候,难免会需要根据条件来注册Bean。

Spring框架提供了很多@Conditional供我们使用,主要有:

@ConditionalOnBean:仅仅在当前上下文中存在某个对象时,才会实例化一个Bean;
@ConditionalOnClass:某个class位于类路径上,才会实例化一个Bean;
@ConditionalOnExpression:当表达式为true的时候,才会实例化一个Bean;
@ConditionalOnMissingBean:仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean;
@ConditionalOnMissingClass:某个class类路径上不存在的时候,才会实例化一个Bean;
@ConditionalOnNotWebApplication:不是web应用;

今天就简单分析到这里,更细节的内容大家可以再沿着这个思路,进一步分析源码。对于每一个技术实现,我们不仅要知其然,还要知其所以然。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值