自动装配是SpringBoot的核心功能,它将开发人员从Bean的繁复配置中解脱出来。那么SpringBoot具体起什么作用呢?以Spring MVC为例,不采用SpringBoot时,需要配置视图解析器,文件解析器,请求适配器等各种Bean,如果采用SpringBoot,则只需集成spring-boot-starter-web依赖模块即可。同样如果使用数据库,在非SpringBoot工程中,我们需要配置dataSource、sessionFactory、transactionManager等各种Bean。
本文将逐步解析SpringBoot自动装配原理,首先从@SpringBootApplication启动注解入手,然后逐层分析SpringBoot怎么利用注解实现Bean自动装配的。
注解@SpringBootApplication一般作用在启动类上,由三个重要的Annotation组成@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan,其中@SpringBootConfiguration实际上就是代表了一个配置类,相当于一个beans.xml文件,@ComponentScan的功能其实就是自动扫描并加载符合条件的组件或bean定义,最终将这些bean 定义加载到Spring IoC容器中,@EnableAutoConfiguration代表开启SpringBoot的自动装配。
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM,
classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@AliasFor(annotation = EnableAutoConfiguration.class)
Class>[] exclude() default {};
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
//根据包路径扫描
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
//直接根据 class 类扫描
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class>[] scanBasePackageClasses() default {};
}
继续深入了解@EnableAutoConfiguration注解,其中最关键的要属@Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到SpringBoot创建的IoC容器。同时借助于Spring的一个工具类SpringFactoriesLoader,去实现@EnableAutoConfiguration注解自动配置。
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
//按类型排除不需要自动装配的类
Class>[] exclude() default {};
//按名称排除不需要自动装配的类
String[] excludeName() default {};
}
查看AutoConfigurationImportSelector源码,可以看出该类实现了很多的xxxAware和DeferredImportSelector,并且所有的Aware都优先于selectImports方法执行。
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered {
......
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 加载META-INF/spring-autoconfigure-metadata.properties文件
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;
}
// 获取注解@EnableAutoConfiguration的属性及其值
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 查找classpath下所有的META-INF/spring.factories文件,并从中读取org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,将其封装成List返回
List configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 对上一步返回的List configurations中的元素去重、排序
configurations = removeDuplicates(configurations);
// 依据attributes中的属性值排除一些特定的类
Set exclusions = getExclusions(annotationMetadata, attributes);
// 对上一步中所得到的List configurations进行过滤,过滤的依据是条件匹配
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
protected List getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
return configurations;
}
......
}
SpringFactoriesLoader属于Spring框架私有的一种扩展方案,主要功能就是从指定的配置文件META-INF/spring.factories中加载配置,即根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration作为查找的Key,获取对应的一组@Configuration类。
综合所述,@EnableAutoConfiguration作用就是从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的配置项,通过反射实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后将这些都汇总成为一个实例并加载到IOC容器中。
但并不是所有EnableutoConfiguration的功能配置类都会生效,Spring会从classpath中查找是否有该配置项的依赖类(也就是pom.xml必须有对应功能的依赖包),并且配置类里面注入了默认属性值类,功能类可以引用并赋默认值。