首先我们看下Spring Boot Starter的Maven依赖,在图中不用想我们就可以才出来自动配置一定主要是由spring-boot-autoconfigure
模快来实现的,由此,我们着重研究spring-boot-autoconfigure
的原理就可以推断出Spring Boot的自动配置原理,Start!
@SpringBootApplication
注解依赖图
1 开启自动配置
开启自动配置主要是由@EnableAutoConfiguration
注解来实现的
翻下源码:
ElementType.TYPE)
(RetentionPolicy.RUNTIME)
(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* 排除特定的自动配置类,使它们不会被应用
*/
Class<?>[] exclude() default {};
/**
* 根据类名排除特定的自动配置类,使它们不会被应用
*/
String[] excludeName() default {};
}
(
很容易我们发现在这里它导入了一个AutoConfigurationImportSelector
的类,点进去看下
他有几个很重要的方法,粘贴下:
/**
* 判断是否开启自动配置,直接返回true
*/
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass() == AutoConfigurationImportSelector.class) {
return getEnvironment().getProperty(
EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,
true);
}
return true;
}
/**
* 返回应该考虑的自动配置类名. 默认情况下该方法将使用 {@link SpringFactoriesLoader}
*/
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
// 这一步非常重要,加载Spring Boot自动配置的核心文件
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;
}
/**
* 检查排除的自动配置类
*/
private void checkExcludedClasses(List<String> configurations,
Set<String> exclusions) {
List<String> invalidExcludes = new ArrayList<>(exclusions.size());
for (String exclusion : exclusions) {
if (ClassUtils.isPresent(exclusion, getClass().getClassLoader())
&& !configurations.contains(exclusion)) {
invalidExcludes.add(exclusion);
}
}
if (!invalidExcludes.isEmpty()) {
handleInvalidExcludes(invalidExcludes);
}
}
我们顺藤摸瓜,看下SpringFactoriesLoader
类
public final class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap();
}
直接看到了加载的核心配置文件META-INF/spring.factories
,然后其他两个属性分别是日志和缓存的声明
我们再简单的看下spring.factories
文件
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
......
发现声明了好多配置项和自动配置类,这足以说明自动配置并没有多么高大上,只是Spring团队的开发者们一步一步用各种方式实现的,致敬!
2 条件注解
Conditional翻译为‘有条件的’
我们挑几个重要的来讲:
- @Conditional:按照一定的条件进行判断,满足条件给容器注册bean
- @ConditionalOnClass:按照有无该类条件进行判断,满足条件给容器注册bean
- @ConditionalOnBean:按照有无该Bean条件进行判断,满足条件给容器注册bean
- @ConditionalOnMissingBean:按照有无该Bean条件进行判断,满足条件给容器注册bean
- @ConditionalOnProperty:按照有无该Property条件进行判断,满足条件给容器注册bean