顾名思义,Autoconfigure 就是自动配置的意思,SpringBoot 通过 spring-boot-autoconfigure 体现了 “约定优于配置” 这一设计原则!spring-boot-autoconfigure 也是 SpringBoot 最重要的模块之一!
SpringBoot 则可以依据 classpath 里面的依赖内容来自动配置 Bean 到 IOC 容器,Auto-configuration 会尝试推断哪些 Beans 是用户可能会需要的。比如如果HSQLDB 包在当前 classpath 下,并且用户并没有配置其他数据库链接,这时候 Auto-configuration 功能会自动注入一个基于内存的数据库连接到应用的 IOC 容器。但是要开启这个自动配置功能需要添加 @EnableAutoConfiguration 注解。
~
本篇内容包括:spring-boot-autoconfigure 模块介绍、关于 @EnableAutoConfiguration 注解、spring-boot-autoconfigure 模块总结
顾名思义,Autoconfigure 就是自动配置的意思,SpringBoot 通过 spring-boot-autoconfigure 体现了 “约定优于配置” 这一设计原则!spring-boot-autoconfigure 也是 SpringBoot 最重要的模块之一!
SpringBoot 则可以依据 classpath 里面的依赖内容来自动配置 Bean 到 IOC 容器,Auto-configuration 会尝试推断哪些 Beans 是用户可能会需要的。比如如果HSQLDB 包在当前 classpath 下,并且用户并没有配置其他数据库链接,这时候 Auto-configuration 功能会自动注入一个基于内存的数据库连接到应用的 IOC 容器。但是要开启这个自动配置功能需要添加 @EnableAutoConfiguration 注解。
spring-boot-autoconfigure 位于 spring-boot 项目中。
spring-boot-autoconfigure 在 源码地址为:https://github.com/spring-projects/spring-boot/tree/v2.1.0.RELEASE/spring-boot-project/spring-boot-autoconfigure
@EnableAutoConfiguration 注解,此注解自动载入应用程序所需的所有Bean,这依赖于 SpringBoot 在类路径中的查找。
# @EnableAutoConfiguration 的源码:
package org.springframework.boot.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
@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 {};
}
通过源码部分可以看到有一特殊的注解——@Import,EnableAutoConfiguration 注解 Import 了一个 AutoConfigurationImportSelector 实例
AutoConfigurationImportSelector类(implement ImportSelector),实现了 selectImports()
方法,用来筛选被 Import 的 Configuration 类(减去exclude等)
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
//......
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 如果AutoConfiguration没开,返回{}
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 将spring-autoconfigure-metadata.properties的键值对配置载入到PropertiesAutoConfigurationMetadata对象中并返回
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
// 基于各种配置计算需要import的configuration和exclusion
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
// 判断AudoConfiguration是否开启
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass() == AutoConfigurationImportSelector.class) {
// 如果配置文件中有"spring.boot.enableautoconfiguration",返回该字段的值;否则返回true
return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
}
return true;
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取注解的属性值
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 从META-INF/spring.factories文件中获取EnableAutoConfiguration所对应的configurations
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 去重,List转Set再转List
configurations = removeDuplicates(configurations);
// 从注解的exclude/excludeName属性中获取排除项
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 对于不属于AutoConfiguration的exclude报错
checkExcludedClasses(configurations, exclusions);
// 从configurations去除exclusions
configurations.removeAll(exclusions);
// 由所有AutoConfigurationImportFilter类的实例再进行一次筛选,去
configurations = filter(configurations, autoConfigurationMetadata);
// 把AutoConfigurationImportEvent绑定在所有AutoConfigurationImportListener子类实例上
fireAutoConfigurationImportEvents(configurations, exclusions);
// 返回(configurations, exclusions)组
return new AutoConfigurationEntry(configurations, exclusions);
}
// ......
}
可见 selectImports() 是 AutoConfigurationImportSelector 的核心函数,其核心功能就是获取 spring.factories 中 EnableAutoConfiguration 所对应的 Configuration 类列表,由 @EnableAutoConfiguration 注解中的 exclude/excludeName 参数筛选一遍,再由 AutoConfigurationImportFilter 类所有实例筛选一遍,得到最终的用于 Import 的 configuration 和 exclusion。
该函数是被谁调用的呢?在 org.springframework.context.annotation.ConfigurationClassParser 类中被 processImports() 调用,而 processImports() 函数被d oProcessConfigurationClass() 调用。
@EnableAutoConfiguration 作用:
org.springframework.boot.autoconfigure.EnableAutoConfiguration key
对应的配置项加载到 spring 容器 只有 spring.boot.enableautoconfiguration 为 true(默认为true)的时候,才启用自动配置其内部实现的关键点有:
SpringBoot 通过 spring-boot-autoconfigure 体现了“约定优于配置”这一设计原则,而 spring-boot-autoconfigure 主要用到了 spring.factories 和几个常用的注解条件来实现自动配置,思路很清晰也很简单。
SpringBoot AutoConfigure 替代了 XML 风格的配置文件,带来了前所未有的体验。spring-boot-autoconfigure 模块基于 SpringFramework 和 SpringBoot 提供的基础设施,构建类配置 Bean+属性文件 配置行为的配置方式,Java 类配置 Bean 为我们提供了更好的编程体验,属性文件配置行为的方式使这种方式拥有跟XML外部配置文件配置方式同样的灵活性。
SpringBoot AutoConfigure 在 SpringFramework 和 SpringBoot 提供的基础设施上做了很多的扩展工作:
所有的 AutoConfiguration 的具体实现包括两部分(主要文件也是这两类,剩下的是一些工具):
AutoConfiguration 也是 Configuration,被 @Configuration 注解,只不过 spring-boot-autoconfigure 模块内置的 AutoConfiguration 被配置到了 spring.factories 文件中,启动的时候自动配置。