上一篇对Spring中@Import注解从常规使用和底层源码角度完成分析
SpringBoot自动装配原理以及starter技术(上),本节将在@Import注解基础上分析自动装配原理,本节安排如下:
- @SpringBootApplication
- DeferredImportSelectorHandler#handle
- DeferredImportSelectorGrouping#getImports
- AutoConfigurationImportSelector#getAutoConfigurationEntry
- 实战自定义starter
- 总结
1、@SpringBootApplication
先看看注解的定义,如下所示:
@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 {
@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 {};
}
可以看到@SpringBootApplication属于符合注解,由多个元注解组成,简单介绍一下几个较为复杂的元注解:
-
@SpringBootConfiguration
@SpringBootConfiguration等价于@Configuration -
@EnableAutoConfiguration
复合注解,由@AutoConfigurationPackage和
@Import组成,@AutoConfigurationPackage主要作用是解析出当前主类所在的包名,@Import则是导入AutoConfigurationImportSelector(实现DeferredImportSelector接口,DeferredImportSelector继承ImportSelector) -
ComponentScan
扫描包名、自定义排除Filter、包含Filter等;
2、DeferredImportSelectorHandler.handle
还记得上一篇文章中这张图?
由上面@SpringBootApplication注解可以看到,AutoConfigurationImportSelector(作为DeferredImportSelector的实现类)由@Import导入,因此在处理@Import注解时将会被特殊处理,执行DeferredImportSelectorHandler的hanle方法;
可以看到handle将AutoConfigurationImportSelector存入deferredImportSelectors中。
- DeferredImportSelectorHandler.process
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
//1、DeferredImportSelectorHolder排序
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
//2、将DeferredImportSelectorHolder注册到DeferredImportSelectorGroupingHandler
deferredImports.forEach(handler::register);
//3、处理自动装配
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
接下来看一下register方法,主要将deferredImport按ImportGroup分类,然后再存入grouping中。
- DeferredImportSelectorHandler.register
public void register(DeferredImportSelectorHolder deferredImport) {
//自动装配deferredImport.getImportSelector为AutoConfigurationImportSelector,getImportGroup为AutoConfigurationGroup
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
//computeIfAbsent不覆盖 返回覆盖后的
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
//将deferredImport加到DeferredImportSelectorGrouping里面的deferredImports list里面
grouping.add(deferredImport);
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
然后接下来再看handler.processGroupImports()方法:
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
//getImports得到需要导入的类
grouping.getImports().forEach(entry -> {
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
/**
* 将自动装配导入的类执行import处理逻辑,通过import处理逻辑标记当前自动装配类由configurationClass导入
* 便于后续ConfigurationClassBeanDefinitionReader.loadBeanDefinitions处理:如果当前ConfigurationClass是被import,
* 则通过registerBeanDefinitionForImportedConfigurationClass生成beanDefinition注册到beanDefinitionMap中
*
* 则自动装配装配的是beanDefiniton,
*/
processImports(configurationClass, asSourceClass(configurationClass),
asSourceClasses(entry.getImportClassName()), false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
//省略非关键代码
}
});
}
}
- DeferredImportSelectorGrouping.getImports
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
//执行process
this.group.process(deferredImport.getConfigurationClass().getMetadata(),// this.group.process
deferredImport.getImportSelector());
}
return this.group.selectImports();
}
接下来重点看AutoConfigurationGroup的process方法。
3、DeferredImportSelectorGrouping#getImports
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
/**
* getAutoConfigurationMetadata:
* 加载META-INF/spring-autoconfigure-metadata.properties中的元素,找到自动装配类注入容器所需要依赖的类;*/ .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
//将自动装配类注入类以及引入的元注解存入map
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
}
4、AutoConfigurationImportSelector#getAutoConfigurationEntry
getAutoConfigurationEntry方法可以分成6步:
A、获取@EnableAutoConfiguration注解属性;
B、从当前classPath下面获取所有META-INF下
spring.factories中EnableAutoConfiguration所对应的value作为自动装配的候选类;
C、利用hashSet对候选类进行去重;
D、对候选类排除@EnableAutoConfiguration注解中exclude和excludeName所对应的类;
E、利用filter方法对候选类进行过滤;
F、发布装配导入事件;
接下来重点看filter过滤方法:
总共有三种类型判断:OnClassCondition、OnBeanCondition、OnWebApplicationCondition,此处只以OnClassCondition为例,其他类似;
OnClassCondition:
先判断是否为多核,如果是多核则将候选类列表一分为二,启动新线程执行前半段,主线程解析后半段。解析完毕后则将解析结果复制到最终结果中,解析来重点关注如何解析:
候选类+ConditionalOnClass作为key从spring-autoconfigure-metada.properties文件中获取当前候选类加载到容器所需要的依赖类。
通过ClassNameFilter.MISSING.matches判断依赖类是否存在:
通过类加载器能否成功加载依赖类判断依赖类是否存在。如果成功加载,则说明依赖类存在,则候选类可以加载到容器。
以上的流程可以通过下图进行总结:
5、实战自定义starter
- 自定义starter工程
- 线程池参数
- 线程池Bean
- 装配bean加入spring.factories文件中
将以上生成如下jar包:
接下来测试自动装配:
- 测试demo
- 配置线程池参数
thread.config.core-pool-size=8
thread.config.maximum-pool-size=64
thread.config.keep-alive-time=60
- 注入线程池
- 启动
- 结果
6、总结
在上一节分析@Import的基础上,本节对自动装配原理进行分析,其原理可以归纳为:
A、@EnableAutoConfiguration注解引入AutoConfigurationImportSelector类;
B、获取所有spring.factories文件中的org.springframework.boot.autoconfigure.EnableAutoConfiguration所对应的value作为自动装配类的候选列表;
C 、获取spring.factories中org.springframework.boot.autoconfigure.AutoConfigurationImportFilter中所对应的value作为过滤器Filter(OnBeanCondition、OnClassCondition、OnWebApplicationCondition);
D、加载spring-autoconfig-metadata.properties获得每个候选类所需要依赖类或者依赖bean;
E 、针对每个候选类,依次用每个过滤filter判断候选类是否匹配。如果所有Filter匹配,则作为可装配类返回;
F、遍历可装配类列表,执行processImports逻辑,标记当装配类是通过import导入。在ConfigurationClassBeanDefinitionReader.loadBeanDefinitions中,如果判断为通过import导入,则执行ConfigurationClassBeanDefinitionReader.registerBeanDefinitionForImportedConfigurationClass将自动装配类生成beanDefinition注册到beanDefinitionMap中;
通过以上梳理,则可以回答上一节的两个问题:
如何自动?
自动是通过@EnableAutoConfiguration注解实现;
装配什么?
装配的是beanDefiniton(将可装配类的beanDefinition注册到beanDefinitionMap中)。