首先我们看下Spring Boot Starter的Maven依赖,在图中不用想我们就可以才出来自动配置一定主要是由spring-boot-autoconfigure
模快来实现的,由此,我们着重研究spring-boot-autoconfigure
的原理就可以推断出Spring Boot的自动配置原理,Start!
@SpringBootApplication
注解依赖图
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 {}; }
很容易我们发现在这里它导入了一个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
3 启动配置流程总结
4 总体流程图