解析启动类流程主要分为三大块:解析类路径下用户自定义的所有类、解析SPI机制从spring.factories文件中加载获取到的类、以及创建所有候选类的BeanDefinitions「用户自定义的类在扫描包路径时触发BeanDefinitions的初始化、spring.factories文件中的候选类以及其间接加载的候选类单独触发BeanDefinitions的初始化」。
- 先注册用户自定义类其BeanDefinitions至bean 工厂中。
- 再次通过ImportSelector延迟类型之DeferredImportSelector利用SPI手段加载得到全部spring.factories文件中配置的全部候选类。
- 遍历步骤2每一个候选类,依次分析其存在的@Component、@Import、@Bean等相关注解再次导入的候选类。
- 注册步骤2、步骤3的候选类其BeanDefinitions至bean 工厂中。
public class ConfigurationClassPostProcessor{
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
...
do {
//ConfigurationClassParser#parse
parser.parse(candidates);
parser.validate();
...
}
...
// ===================== 注册自动装配候选类以及其@bean注解对应BeanDefinition至bean工厂中
// 参考第7节
this.reader.loadBeanDefinitions(configClasses);
while (!candidates.isEmpty());
}
}
AnnotatedGenericBeanDefinition类型的BeanDefinition。这种类型的BeanDefinition提供基于元数据、元注解分析的StandardAnnotationMetadata。
由于SpringBoot启动过程中存在诸多元数据、元注解的解析,其中AnnotatedGenericBeanDefinition类型的BeanDefinition初始化了ClassMetadata、AnnotatedTypeMetadata两种类型解析器StandardAnnotationMetadata
ImportSelector延迟类型之DeferredImportSelector:加载类路径下自动装配的全部候选类,并且解析每一个候选类是否存在@Component、@ComponentScans、@Import等相关注解。
class ConfigurationClassParser {
private final DeferredImportSelectorHandler deferredImportSelectorHandler = new DeferredImportSelectorHandler();
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());
}
...
}
}
//【自定义类处理完毕】===========================延迟类型的ImportSelector处理器
this.deferredImportSelectorHandler.process();
}
//metadata:StandardAnnotationMetadata
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// 此处存在去重逻辑,避免重复处理候选类
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
...
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
@Nullable
protected SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter){
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass, filter);
}
// Process any @PropertySource annotations
...
// Process any @ComponentScan annotations
AnnotationMetadata am = sourceClass.getMetadata();
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(am, ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() && !conditionEvaluator.shouldSkip(am, ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
String className = sourceClass.getMetadata().getClassName();
//==========================================将扫描类路径下得到的用户自定义类的BeanDefinition注册到 bean工厂中
Set<BeanDefinitionHolder> scannedBeanDefinitions = componentScanParser.parse(componentScan, className);
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
// 解析每个自定义类存在的@Component、@PropertySource、@ComponentScan...等注解
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
// Process any @ImportResource annotations
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
return null;
}
}
configCandidates:AnnotatedBeanDefinition类型的启动类。
shouldSkip:判断当前候选类是否存在Conditional注解。正常情况下启动类不存在的。
最终结果:符合条件的类最终都会添加到Map类型的集合ConfigurationClasses中。
涉及的注解解析流程如下:
- 解析@Conditional注解。
- 解析@Component注解。
- 解析@PropertySources注解。
- 解析@ComponentScans注解。
- 解析@Import注解。
- 解析@ImportResource注解。
- 解析@Bean注解。
SpringBoot中解析任何一个类「包括上述注解解析到的类」都会执行ConfigurationClassParser#processConfigurationClass方法。 就是因为每个候选类最终都会作为Map类型的集合ConfigurationClasses中元素。
deferredImportSelectorHandler.process:解析核心类AutoConfigurationImportSelector过程中利用SPI机制加载spring.factories文件中配置的候选的装配类。 这些装配类的解析同样会使用当前文的全文逻辑。具体参考
1、解析@Conditional注解
该接口的实现类【OnBeanCondition、OnClassCondition、OnPropertyCondition】等都存在一个用于排序的注解`@Order`。
@Order注解其value取值越大对应排序时的优先级越低。
使用方式之直接方式即`自定义实现接口Condition的子类 | 直接@Conditional`,间接方式之@Conditional:
- @ConditionalOnBean【@Conditional(OnBeanCondition.class)】。
- @ConditionalOnMissingBean【@Conditional(OnBeanCondition.class)】。
- @ConditionalOnMissingClass【@Conditional(OnClassCondition.class)】。
- @ConditionalOnClass【@Conditional(OnClassCondition.class)】。
- @ConditionalOnProperty【@Conditional(OnPropertyCondition.class)】。
通过组合注解方式使用时其@Conditional注解属性class【OnBeanCondition、OnClassCondition、OnPropertyCondition】都会对应的赋值实现接口Condition的子类。
作用:主要是利用接口Condition的功能判断【直接方式、间接方式】配置类是否满足条件。
主要解析的是当前类的元注解信息「AnnotatedTypeMetadata」。
- 如果当前类不存在@Conditional相关的注解,则返回false。
- 如果存在则根据Condition接口相关判定条件裁决当前类是否允许添加到Map类型的集合ConfigurationClasses中。
如果返回true,当前类则不会添加到集合ConfigurationClasses中,也即Spring IOC容器中更不会存在。
如果这些注解存在于类内部的方法上【通常是协同@Bean注解】,符合条件的会将@Bean的bean定义信息添加到beanDefinitionMap。后续用于实例并初始化。
class ConditionEvaluator {
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
...
List<Condition> conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
}
- getConditionClasses:获取当前类所有@Conditional「直接方式、间接方式」其value属性设置的所有condition接口的子类。
- condition.matches:匹配condition接口每个子类的matches方法,只要存在一个false则表明当前类则不会添加到集合ConfigurationClasses中。更不会添加到IOC容器中。
2.解析@Component注解
如果当前类存在的组合注解中存在@Component注解都会触发。
memberClasses:获取当前类中的所有内部类。集合中所有内部类按照位置顺序从后往前依次添加到集合中。
- 排除掉非「配置类~Full模式&Lite模式」的候选类。
- 根据order接口进行排序「值越大优先级越低」。
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
if (!memberClasses.isEmpty()) {
List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
for (SourceClass memberClass : memberClasses) {
// 内部类成为候选类的条件
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
candidates.add(memberClass);
}
}
// 所有内部类排序,决定内部类触发的先后顺序
OrderComparator.sort(candidates);
for (SourceClass candidate : candidates) {
...
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
}
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
if (metadata.isInterface()) {
return false;
}
for (String indicator : candidateIndicators) {//4种类型注解:Import、ImportResuource、Component、ComponentScan
if (metadata.isAnnotated(indicator)) {
return true;
}
}
return metadata.hasAnnotatedMethods(Bean.class.getName());
}
3.解析@ComponentScan注解
- componentScanParser.parse:扫描包路径「basePackage~启动类所在的包路径」下用户自定义的所有类。
- 遍历步骤1中的每个类。
- 最终递归方式回调ConfigurationClassParser#processConfigurationClass。
public class ClassPathScanningCandidateComponentProvider{
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
private final List<TypeFilter> excludeFilters = new ArrayList<>();
private final List<TypeFilter> includeFilters = new ArrayList<>();
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
// 获取到类路径下全部的类
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
for (Resource resource : resources) {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// 遍历每一个类,判断是否满足候选类特性
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
candidates.add(sbd);
}
}
}
return candidates;
}
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
}
默认情况下excludeFilters主要包含:AutoConfigurationExcludeFilter、TypeExcludeFilter。其中前者主要判断当前类是否存在注解@Configuration,后者应该是方便使用方自行扩展类的Filter。
默认情况下includeFilters主要包含:AnnotationTypeFilter,主要判断当前类是否存在注解@Component。
通常情况下候选类只要存在@Configuration、@Component任意一个注解都会被IOC容器自行管理的类。
4.解析@Import注解
通过@Import注解注入Bean的方式有如下三种:
- 基于Configuration Class。例如:@Import({ NoOpMeterRegistryConfiguration.class}),导入的候选类只是普通的配置类。
- 基于ImportSelector接口。
- 基于ImportBeanDefinitionRegistrar接【AutoConfigurationPackages.Registrar.class】。特例参考AOP、事务相关功能。
class ConfigurationClassParser {
DeferredImportSelectorHandler deferredImportSelectorHandler = new DeferredImportSelectorHandler();
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
for (SourceClass candidate : importCandidates) {// 当前类通过import注解导入的全部候选类
// 候选类 是接口ImportSelector的子类
if (candidate.isAssignable(ImportSelector.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);
// 候选类 同时也是 接口DeferredImportSelector的子类 -- 启动类注解import导入的AutoConfigurationImportSelector
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}else {
// 直接调用候选类核心方法之selectImports,通过该方法再次得到需要加载到IOC容器的相关新的候选类
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
// 递归调用分析新的候选类是否为ImportSelector类型 or 普通的配置类
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
// 候选类 是接口ImportBeanDefinitionRegistrar的子类
}else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(egistrar, this.environment, this.resourceLoader, this.registry);
// 候选类添加到 当前配置类configClass其importBeanDefinitionRegistrars属性中
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}else {
// 候选类 是普通的配置类
String className = candidate.getMetadata().getClassName();
this.importStack.registerImport(currentSourceClass.getMetadata(), className);
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
}
DeferredImportSelectorHandler:延迟加载接口ImportSelector导入候选类的handler。通过spi机制加载spring.factories文件下的目标候选类。
延迟是提现在何处呢?
- 如果当前配置类利用@Import导入的候选类是接口ImportSelector的子类但不是接口DeferredImportSelector的子类,则执行核心方法【selectImports----spi机制加载spring.factories文件下的目标候选类】时机如上文所示。
- 如果当前配置类利用@Import导入的候选类只是接口ImportSelector的子类则马上通过selectImports方法再次获取该子类利用@Import导入的候选类。
5.解析@Bean注解
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
...
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
...
}
获取当前ConfigurationClass类通过@Bean注解注入的实例集合。
6.SourceClass
为啥多此一举需要把候选类封装为SourceClass?
因为在SpringBoot中候选类的加载分为两部分:JVM & ASM。
- 如果候选类已经通过反射方式获取到.class文件【启动类】,则直接将该候选类赋值为StandardAnnotationMetadata内部的内省类【候选类】。
- 如果候选类尚为编译后的.class文件,则通过类名判断是否为"java."包下的类:
- 是,其实就是启动类加载器加载的类,直接通过反射获取。
- 否,则通过ASM【SimpleMetadataReader】方式将候选类作为资源加载。
private class SourceClass implements Ordered {
public SourceClass(Object source) {
this.source = source;
if (source instanceof Class) {//内省类处理
this.metadata = AnnotationMetadata.introspect((Class<?>) source);
}
else {
this.metadata = ((MetadataReader) source).getAnnotationMetadata();
}
}
public ConfigurationClass asConfigClass(ConfigurationClass importedBy) {
if (this.source instanceof Class) {
return new ConfigurationClass((Class<?>) this.source, importedBy);
}
return new ConfigurationClass((MetadataReader) this.source, importedBy);
}
...
}
importedBy:表示当前的sourceClass是被importedBy的@import引入的。
7.延迟候选类的BeanDefinitions
class ConfigurationClassBeanDefinitionReader {
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
// 集合configurationModel元素为全量bean的类信息
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
...
//当前配置类是通过注解@Import导入则注册配置类其BeanDefinition至bean 工厂中
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// 将配置类中通过注解@Bean注入的bean,其BeanDefinition注册至bean 工厂中
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 如果配置类是 接口ImportBeanDefinitionRegistrars 的子类则将该候选类的BeanDefinition注册至bean 工厂中
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
}