16、Spring~配置类
- 配置类源码解析
- ConfigurationClassPostProcessor类
- postProcessBeanDefinitionRegistry()方法
- processConfigBeanDefinitions()方法
- ConfigurationClassUtils类
- checkConfigurationClassCandidate()方法
- ConfigurationClassParser类
- parse()方法
- processConfigurationClass()方法
- doProcessConfigurationClass()方法
- processImports()方法
配置类源码解析
Spring容器在启动过程中,在BeanFactory创建之后,会执行BeanFactoryPostProcessors,这里会拿到之前Spring容器自己设置的ConfigurationClassPostProcessor,Spring容器详细的启动过程请移步至《Spring~容器启动过程》,我们接下来详细分析ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry()方法,废话不多说,上代码:
ConfigurationClassPostProcessor类
postProcessBeanDefinitionRegistry()方法
postProcessBeanDefinitionRegistry()方法详解
/*** Derive further bean definitions from the configuration classes in the registry.*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {int registryId = System.identityHashCode(registry);if (this.registriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);}if (this.factoriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);}this.registriesPostProcessed.add(registryId);// 解析配置类processConfigBeanDefinitions(registry);
}
通过上述代码,可以看到,这里会调用processConfigBeanDefinitions()方法
processConfigBeanDefinitions()方法
processConfigBeanDefinitions()方法详解
/*** Build and validate a configuration model based on the registry of* {@link Configuration} classes.*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {List<BeanDefinitionHolder> configCandidates = new ArrayList<>();String[] candidateNames = registry.getBeanDefinitionNames();for (String beanName : candidateNames) {BeanDefinition beanDef = registry.getBeanDefinition(beanName);if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {if (logger.isDebugEnabled()) {logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);}}// 什么是配置类?else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}}// Return immediately if no @Configuration classes were foundif (configCandidates.isEmpty()) {return;}// Sort by previously determined @Order value, if applicable// 通过@Order可以排序,升序排序,order越小越靠前configCandidates.sort((bd1, bd2) -> {int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());return Integer.compare(i1, i2);});// Detect any custom bean name generation strategy supplied through the enclosing application contextSingletonBeanRegistry sbr = null;if (registry instanceof SingletonBeanRegistry) {sbr = (SingletonBeanRegistry) registry;if (!this.localBeanNameGeneratorSet) {// 可以预先往单例池中添加一个CONFIGURATION_BEAN_NAME_GENERATOR的BeanNameGenerator类型的bean// 可以用来作为扫描得到的Bean和import导入进来的Bean的beanNameBeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);if (generator != null) {this.componentScanBeanNameGenerator = generator;this.importBeanNameGenerator = generator;}}}if (this.environment == null) {this.environment = new StandardEnvironment();}// Parse each @Configuration classConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());// 递归解析配置类,有可能通过解析一个配置类,得到了其他的配置类,比如扫描和Importtdo {StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");// 解析配置类,会把每个BeanDefinitionHolder首先封装为ConfigurationClass// 在这个过程中会进行扫描、导入等步骤,从而会找到其他的ConfigurationClass// 解析配置类的结果是什么?// 触发扫描parser.parse(candidates); // AppConfig.class--->BeanDefinitionparser.validate();// configClasses相当于就是解析之后的结果Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}// 把所有的ConfigurationClass加载成BeanDefinition,通过情况下一个配置类会对应一个BeanDefinition,不过也有可能一个配置类对应多个BeanDefinition// 比如一个配置类中有多个@Bean,一个配置配置了@ImportResourcethis.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();// candidates中存的是BeanDefinition,configClasses中存的是ConfigurationClasscandidates.clear();// 如果发现BeanDefinition增加了,则有可能增加了配置类if (registry.getBeanDefinitionCount() > candidateNames.length) {String[] newCandidateNames = registry.getBeanDefinitionNames();Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));Set<String> alreadyParsedClasses = new HashSet<>();for (ConfigurationClass configurationClass : alreadyParsed) {alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());}for (String candidateName : newCandidateNames) {if (!oldCandidateNames.contains(candidateName)) {BeanDefinition bd = registry.getBeanDefinition(candidateName);// 检查多出来的BeanDefinition是不是配置类,需不需要解析if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&!alreadyParsedClasses.contains(bd.getBeanClassName())) {candidates.add(new BeanDefinitionHolder(bd, candidateName));}}}candidateNames = newCandidateNames;}}while (!candidates.isEmpty());// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classesif (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());}if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {// Clear cache in externally provided MetadataReaderFactory; this is a no-op// for a shared cache since it'll be cleared by the ApplicationContext.((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();}
}
通过上述代码,我们可以看到:
- 这里会拿到现在所有的BeanDefinitionName,此时BeanDefinitionName只有6个(我们传的配置类和Spring容器设置的5个);
- 遍历这些BeanDefinitionName,通过ConfigurationClassUtils类的checkConfigurationClassCandidate()方法判读是否是配置类;拿到配置类后,放入集合中;
- 判断集合是空,说明没有配置类,返回;
- 对集合中配置类进行排序;
- 再往下,到注释标记“spring.context.config-classes.parse”,开始解析配置类;
- 这里是通过递归,解析配置类,有可能通过解析一个配置类,得到了其他的配置类,比如扫描和Import;
- 调用ConfigurationClassParser类的parse()方法,解析配置类,解析完会把所有的配置类方如一个集合;
- 拿到集合中所有的配置类,进行遍历;
- 如果当前ConfigurationClass是通过@Import注解导入进来的对象,会生成BeanDefinition;
- 解析ConfigurationClass对象的importBeanDefinitionRegistrars属性、importedResources属性、beanMethods属性,生成BeanDefinition对象;
- 判断新增的BeanDefinition对象是不是配置类,是话继续解析新增BeanDefinition对象;
ConfigurationClassUtils类
checkConfigurationClassCandidate()方法
checkConfigurationClassCandidate()方法详解
/*** Check whether the given bean definition is a candidate for a configuration class* (or a nested component class declared within a configuration/component class,* to be auto-registered as well), and mark it accordingly.** @param beanDef the bean definition to check* @param metadataReaderFactory the current factory in use by the caller* @return whether the candidate qualifies as (any kind of) configuration class*/
public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {// @Bean定义的配置类Bean是不起作用的String className = beanDef.getBeanClassName();if (className == null || beanDef.getFactoryMethodName() != null) {return false;}// AnnotationMetadata表示某个类的注解信息,但是并一定要加载这个类AnnotationMetadata metadata;// 如果AnnotatedBeanDefinition,则直接取AnnotationMetadataif (beanDef instanceof AnnotatedBeanDefinition &&className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {// Can reuse the pre-parsed metadata from the given BeanDefinition...metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();}// 如果是AbstractBeanDefinition,则解析beanClass得到AnnotationMetadataelse if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {// Check already loaded Class if present...// since we possibly can't even load the class file for this Class.Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||BeanPostProcessor.class.isAssignableFrom(beanClass) ||AopInfrastructureBean.class.isAssignableFrom(beanClass) ||EventListenerFactory.class.isAssignableFrom(beanClass)) {return false;}metadata = AnnotationMetadata.introspect(beanClass);} else {try {MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);metadata = metadataReader.getAnnotationMetadata();} catch (IOException ex) {if (logger.isDebugEnabled()) {logger.debug("Could not find class file for introspecting configuration annotations: " +className, ex);}return false;}}Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());// 存在@Configuration,并且proxyBeanMethods不为false(为true或为null)时,就是Full配置类if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);}// 存在@Configuration,并且proxyBeanMethods为false时,是lite配置类// 或者不存在@Configuration,但是只要存在@Component、@ComponentScan、@Import、@ImportResource四个中的一个,就是lite配置类// 或者不存在@Configuration,只要存在@Bean注解了的方法,就是lite配置类else if (config != null || isConfigurationCandidate(metadata)) {beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);} else {return false;}// It's a full or lite configuration candidate... Let's determine the order value, if any.Integer order = getOrder(metadata);if (order != null) {beanDef.setAttribute(ORDER_ATTRIBUTE, order);}return true;
}
通过上述代码我们可以看到:
- 如果有@Configuration注解,且proxyBeanMethods属性是true,是full配置类;
- 如果@Configuration注解proxyBeanMethods属性是false,或者 isConfigurationCandidate()方法返回的是true,是lite配置类;isConfigurationCandidate方法是判断是否有@Component、@ComponentScan、@Import、@ImportResource注解其中一个或者有@Bean方法,
总结上述代码就是:三种情况满足其中一个就是配置类:
- 有@Configuration注解;
- 有@Component、@ComponentScan、@Import、@ImportResource注解其中一个;
- 有@Bean方法
返回ConfigurationClassPostProcessor类的processConfigBeanDefinitions()方法
ConfigurationClassParser类
parse()方法
parse()方法详解
public void parse(Set<BeanDefinitionHolder> configCandidates) {for (BeanDefinitionHolder holder : configCandidates) {BeanDefinition bd = holder.getBeanDefinition();try {// 解析BeanDefinition所对应的类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);}}// 处理deferredImportSelectors,表示当前所有配置类解析完了之后才执行// deferredImportSelector表示推迟的ImportSelector,正常的ImportSelector是在解析配置类的过程中执行的this.deferredImportSelectorHandler.process();
}protected final void parse(@Nullable String className, String beanName) throws IOException {Assert.notNull(className, "No bean class name for configuration class bean definition");MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER);
}protected final void parse(Class<?> clazz, String beanName) throws IOException {/*** 将配置类的Class和beanName封装成配置类,调用processConfigurationClass方法* */processConfigurationClass(new ConfigurationClass(clazz, beanName), DEFAULT_EXCLUSION_FILTER);
}protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {// 把类的元信息和beanName封装为ConfigurationClassprocessConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
parse()方法,有几个重载方法,不同参数处理逻辑都是调用processConfigurationClass()方法
返回ConfigurationClassPostProcessor类的processConfigBeanDefinitions()方法;
processConfigurationClass()方法
processConfigurationClass()方法详解
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {// 条件注解,就是看有没有类上是否有@Conditional注解,如果有,则进行条件匹配if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {return;}ConfigurationClass existingClass = this.configurationClasses.get(configClass);if (existingClass != null) {if (configClass.isImported()) {// OrderService导入了AccountService,UserService也导入了AccountService,就会符合这个条件if (existingClass.isImported()) {existingClass.mergeImportedBy(configClass);}// Otherwise ignore new imported config class; existing non-imported class overrides it.return;} else {// Explicit bean definition found, probably replacing an import.// Let's remove the old one and go with the new one.this.configurationClasses.remove(configClass);this.knownSuperclasses.values().removeIf(configClass::equals);}}// Recursively process the configuration class and its superclass hierarchy.SourceClass sourceClass = asSourceClass(configClass, filter);// do while 的原因是递归解析父类do {// 解析配置类sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);}while (sourceClass != null);// ConfigurationClass重写了equals方法,只要两个ConfigurationClass对应的className相等就可以this.configurationClasses.put(configClass, configClass);
}
通过上述代码,我们可以看到:
- 如果有@Conditional注解,首先校验条件注解是否满足条件;
- 处理@Import注解导入的Bean;
- 这里有一个do while 循环,是因为,解析完本类后还会去解析它的父类;
- 调用doProcessConfigurationClass()方法解析配置类;
- 所有配置类会封装成一个ConfigurationClass对象,放进统一集合中;
返回parse()方法
doProcessConfigurationClass()方法
doProcessConfigurationClass()方法详解
/*** Apply processing and build a complete {@link ConfigurationClass} by reading the* annotations, members and methods from the source class. This method can be called* multiple times as relevant sources are discovered.** @param configClass the configuration class being build* @param sourceClass a source class* @return the superclass, or {@code null} if none found or previously processed*/
@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)throws IOException {if (configClass.getMetadata().isAnnotated(Component.class.getName())) {// Recursively process any member (nested) classes first// 处理内部类// 在解析一个配置类时,如果类上有@Component,则会判断内部类是不是lite配置类并进行解析,并且会记录为被导入的processMemberClasses(configClass, sourceClass, filter);}// Process any @PropertySource annotationsfor (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class,org.springframework.context.annotation.PropertySource.class)) {if (this.environment instanceof ConfigurableEnvironment) {processPropertySource(propertySource);} else {logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +"]. Reason: Environment must implement ConfigurableEnvironment");}}// Process any @ComponentScan annotations// 会进行扫描,得到的BeanDefinition会注册到Spring容器中,并且会检查是不是配置类并进行解析Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {for (AnnotationAttributes componentScan : componentScans) {// The config class is annotated with @ComponentScan -> perform the scan immediately// 这里就会进行扫描,得到的BeanDefinition会注册到Spring容器中Set<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if neededfor (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}// 检查扫描出来的BeanDefinition是不是配置类(full和lite)if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}// Process any @Import annotations// getImports(sourceClass)会拿到@Import导入的类// 如果导入的是普通类,那么会直接把它当做配置类来解析// 如果导入的是普通ImportSelector,那么会将返回的类再次调用processImports()// 如果导入的是特殊ImportSelector,DeferredImportSelector,那么暂时不会处理,会在解析完所有当前这轮配置类后进行导入,将返回的类再次调用processImports()// 如果导入的是ImportBeanDefinitionRegistrar,那么暂时不会处理,会在解析完所有当前这轮配置类后,将配置类解析成为BeanDefinition之后进行调用processImports(configClass, sourceClass, getImports(sourceClass), filter, true);// Process any @ImportResource annotationsAnnotationAttributes importResource =AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);if (importResource != null) {String[] resources = importResource.getStringArray("locations");Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");for (String resource : resources) {String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);configClass.addImportedResource(resolvedResource, readerClass);}}// Process individual @Bean methods// 解析配置类中的@Bean,但并没有真正处理@Bean,只是暂时找出来Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}// Process default methods on interfaces// 解析配置类所实现的接口中的@Bean,但并没有真正处理@Bean,只是暂时找出来processInterfaces(configClass, sourceClass);// Process superclass, if anyif (sourceClass.getMetadata().hasSuperClass()) {String superclass = sourceClass.getMetadata().getSuperClassName();if (superclass != null && !superclass.startsWith("java") &&!this.knownSuperclasses.containsKey(superclass)) {this.knownSuperclasses.put(superclass, configClass);// Superclass found, return its annotation metadata and recursereturn sourceClass.getSuperClass();}}// No superclass -> processing is completereturn null;
}
通过上述代码,我们可以看到:
- 首先判断如果配置类上有@Component注解,判断内部类是不是配置类是的话继续解析;
- 然后判断如果配置类上有@PropertySource注解,解析.properties配置文件;
- 再往下判断如果配置类上有@ComponentScan注解,会扫描@ComponentScan注解路径下的文件,封装成BeanDefinition对象,遍历扫得到的BeanDefinition对象,判断是不是配置类,是的话继续解析;关于Spring扫描的详细步骤,请移步至《Spring之Bean生命周期~扫描》
- 再往下先调用getImports()方法会拿到@Import导入的类,再调用processImports()方法解析@Import注解;
- 如果配置类上有@ImportResource注解,将所导入的xml文件路径添加到当前配置类的importedResources属性中;
- 如果配置类上有@Bean注解,将@Bean修饰的方法封装为BeanMethod对象,并添加到当前配置类的beanMethods属性中;
- 如果有父类,将父类当成配置类继续解析;
返回processConfigurationClass()方法;
processImports()方法
processImports()方法详解
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,boolean checkForCircularImports) {if (importCandidates.isEmpty()) {return;}if (checkForCircularImports && isChainedImportOnStack(configClass)) {this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));} else {this.importStack.push(configClass);try {for (SourceClass candidate : importCandidates) {// 如果import的类实现了ImportSelector接口if (candidate.isAssignable(ImportSelector.class)) {// Candidate class is an ImportSelector -> delegate to it to determine importsClass<?> candidateClass = candidate.loadClass();ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,this.environment, this.resourceLoader, this.registry);Predicate<String> selectorFilter = selector.getExclusionFilter();if (selectorFilter != null) {exclusionFilter = exclusionFilter.or(selectorFilter);}// 如果import的是DeferredImportSelector,表示推迟导入//if (selector instanceof DeferredImportSelector) {this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);} else {// 如果import的是普通的ImportSelectorString[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());// 继续处理selectImports()所返回的类Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);}}// 如果import的类实现了ImportBeanDefinitionRegistrar接口else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {// Candidate class is an ImportBeanDefinitionRegistrar ->// delegate to it to register additional bean definitionsClass<?> candidateClass = candidate.loadClass();ImportBeanDefinitionRegistrar registrar =ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,this.environment, this.resourceLoader, this.registry);configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());}// 如果import的类就是普通的类else {// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->// process it as an @Configuration classthis.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());// 注意,在asConfigClass方法中,不仅会将candidate生成一个ConfigurationClass,还会记录一下candidate是被哪个类导入的importedByprocessConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);}}} catch (BeanDefinitionStoreException ex) {throw ex;} catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +configClass.getMetadata().getClassName() + "]", ex);} finally {this.importStack.pop();}}
}
通过上述代码,我们可以看到:
- 如果@Import导入的类是空,直接返回;
- 往下经过一系列校验之后,会循环@Import导入的类;
- 如果导入的类实现啦ImportSelector接口,会调用selectImports方法拿到返回结果中的配置类再次进行@Import注解的解析;
- 如果导入的类实现啦ImportBeanDefinitionRegistrar接口,会执行registerBeanDefinitions方法,然后生成BeanDefinition对象,并最终注册到BeanDefinitionRegistry中;
- 如果导入的类没有实现上面两个接口,直接当成一个普通配置类去解析;
返回doProcessConfigurationClass()方法