之前我们已经对@ComponentScan 和 @Import分别进行了详细的介绍和总结
那么接下来,我们来看看Springboot 最核心的注解:@SpringBootApplication, 这也是SpringBoot自动装配相关所需依赖和配置的依仗。
我们先看看他的定义
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
// 排除掉自动配置的class
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
// 排除掉自动配置的全路径类名
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
// 配置扫描的包路径
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
// 配置扫描的类
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
// beanName生成器
@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
// 配置类代理模式:proxyBeanMethods:代理bean的方法
// Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】
// Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}
可以看到,这是一个复合注解,所以接下来我们一个个看
@SpringBootConfiguration
的定义如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}
我们看到了我们熟悉的@Configuration,也就是说,这个东西本质上就是一个配置类
从名字上看,@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 {};
}
这又是一个复合注解,我们继续一个个看
/**
* 用AutoConfigurationPackages注册包。如果没有指定基包或基包类,则注册带注释的类的包。
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
看一下注释,大概意思是把包下的路径注册到spring容器中,如果没有基包(一般就是我们的启动类所在的包路径),则注册带这个注解的包路径。继续往下看
AutoConfigurationPackages.Registrar.class这个类我们可以看看
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
//.....
}
我们可以看得到,这是通过@Import注入对象的其中一种方式实现类的注入
registerBeanDefinitions这里的metadata相当于我们注解的源信息,一般就是我们的启动类
接下来我们来看这个register()方法
通过打断点,我们可以看到,传的packageNames
传的就是启动类所在的包名
registry.containsBeanDefinition(BEAN) 点进去,我们可以看到,并没有匹配的上的,也就是说,启动的时候,容器总并没有包含这个AutoConfigurationPackages的定义
所以这个时候就会直接创建一个BasePackagesBeanDefinition
对象,然后将包名赋值给他的basePackages
属性
static final class BasePackagesBeanDefinition extends GenericBeanDefinition {
private final Set<String> basePackages = new LinkedHashSet<>();
BasePackagesBeanDefinition(String... basePackages) {
setBeanClass(BasePackages.class);
setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
addBasePackages(basePackages);
}
@Override
public Supplier<?> getInstanceSupplier() {
return () -> new BasePackages(StringUtils.toStringArray(this.basePackages));
}
private void addBasePackages(String[] additionalBasePackages) {
this.basePackages.addAll(Arrays.asList(additionalBasePackages));
}
}
从这段代码中,我们可以看到,basePackages
是个set集合,如果容器当中始终只有一个BasePackagesBeanDefinition
对象,只要代码当中添加@AutoConfigurationPackage
注解,就会将注解所在的包名添加到basePackages
集合当中。
这之后,再把AutoConfigurationPackages加到beanDefinitionMap中,value就是刚刚创建的BasePackagesBeanDefinition
总结一下:其实相比于@import
一个一个导,使用@AutoConfigurationPackage相当于一次性把我们主程序路径下的程序都加载到容器中去,这就是这个类的主要作用。
这个注解配置是Spring Boot
的自动装配核心所在
我们先看看AutoConfigurationImportSelector
的定义
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
//.....
}
可以看到AutoConfigurationImportSelector
除了实现一系列的aware
接口获取相关信息之外,就是实现了DeferredImportSelector
接口,DeferredImportSelector
是ImportSelector
的子接口,Deferred
是延迟的意思。
根据之前我们总结的 @Import使用及原理详解 可知,对@Import
的解析会来到ConfigurationClassParser
的#processImports()
,方法代码片段如下:
这里会判断当前selector
是DeferredImportSelector
还是ImportSelector
如果是DeferredImportSelector
,会进入执行this.deferredImportSelectorHandler.handle()
该方法会把DeferredImportSelector
封装成DeferredImportSelectorHolder
放入到this.deferredImportSelectors
集合中。根据DeferredImportSelector
意思来看,就是延迟注入的意思,所以他会等Spring对配置类相关其他注解进行解析完之后,才执行这里的注入逻辑,这可以从DeferredImportSelector
的注释中看得到
也可从ConfigurationClassParser
的#parse()
方法得到验证:
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
// 等上面的解析完成之后再执行
this.deferredImportSelectorHandler.process();
}
来到DeferredImportSelectorHolder
的#process()
方法:
class ConfigurationClassParser {
//....
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
// 遍历调用handler的register()
deferredImports.forEach(handler::register);
// 遍历完之后执行processGroupImports()
handler.processGroupImports();
}
} finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
public void register(DeferredImportSelectorHolder deferredImport) {
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
grouping.add(deferredImport);
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
}
这段代码我们可以很清晰的看到,遍历deferredImportSelectors
集合,每个都会调用handler的#register()
方法
这个集合,我们通过debug,其实也可以看得到,只有这一个。
@Override
public Class<? extends Group> getImportGroup() {
return AutoConfigurationGroup.class;
}
这个方法将AutoConfigurationImportSelector
的内部类AutoConfigurationGroup
添加到groupings
集合当中,并将对应的配置类添加到configurationClasses
当中。
public void add(DeferredImportSelectorHolder deferredImport) {
this.deferredImports.add(deferredImport);
}
继续深入,我们会发现,其实就是添加到deferredImports这个List里面。
遍历完deferredImportSelectors
之后,调用handler.processGroupImports()
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
Predicate<String> exclusionFilter = grouping.getCandidateFilter();
grouping.getImports().forEach(entry -> {
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
exclusionFilter, false);
} catch (BeanDefinitionStoreException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configurationClass.getMetadata().getClassName() + "]", ex);
}
});
}
}
遍历之前放在groupings
中的DeferredImportSelectorGrouping
对象,调用#getImports()
方法,该方法返回的是延迟注入的类名封装成的Entry结点的迭代器对象。
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
return this.group.selectImports();
}
这里我们可以看到,其实封装的就是之前我们register的那些类。
this.group
点进去可以看到,这个group
是AutoConfigurationImportSelector
的内部类AutoConfigurationGroup
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
// 获取自动配置类entry
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(annotationMetadata);
// 放入到autoConfigurationEntries集合中
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
可以看到,该方法得到自动配置结点,将其添加到autoConfigurationEntries集合当中。再遍历自动配置结点的所有配置类的类名,添加到entries集合当中。
protected AutoConfigurationEntry getAutoConfigurationEntry(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 = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
// 封装成AutoConfigurationEntry返回
return new AutoConfigurationEntry(configurations, exclusions);
}
再深入的看看这个getCandidateConfigurations(annotationMetadata, attributes)
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;
}
我们看到了老熟人SpringFactoriesLoader.loadFactoryNames()
,最终在这里加载了META-INF/spring.factories
目录下的自动配置类
拿到所有自动配置类之后回到上面的#processGroupImports()
,grouping.getImports()
获取到所有需要自动装配的类封装对象,接下来会进行一一遍历,调用#processImports()
进行注入,至此Spring Boot
就完成了自动装配。