Spring Boot是如何解析@Configuration配置类的呢?要弄懂这个过程,首先我们需要先了解一个BeanFactoryPostProcessor的概念。
BeanFactoryPostProcessor是什么
1 2 3 4 5 6 7 8 9 10 11 12 13 14
publicinterfaceBeanFactoryPostProcessor{
/** * Modify the application context's internal bean factory after its standard * initialization. All bean definitions will have been loaded, but no beans * will have been instantiated yet. This allows for overriding or adding * properties even to eager-initializing beans. * @param beanFactory the bean factory used by the application context * @throws org.springframework.beans.BeansException in case of errors */ voidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throws BeansException;
/** * Modify the application context's internal bean definition registry after its * standard initialization. All regular bean definitions will have been loaded, * but no beans will have been instantiated yet. This allows for adding further * bean definitions before the next post-processing phase kicks in. * @param registry the bean definition registry used by the application context * @throws org.springframework.beans.BeansException in case of errors */ voidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)throws BeansException;
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size()); do { //解析配置类(处理@ComponentScan,@Import,@Bean方法等注解),但这里实际上只会把@ComponentScan注解扫描的类注册为BeanDefinition parser.parse(candidates); parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content if (this.reader == null) { this.reader = new ConfigurationClassBeanDefinitionReader( registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry()); } //这里会解析上一步parse操作中获取到的ConfigurationClass,比如由@Import生成的配置类、或标注了@Bean注解的方法等注册为BeanDefinition this.reader.loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses);
candidates.clear(); //判断经过loadBeanDefinitions处理后,是否有新增配置类,有则继续解析 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); if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) { candidates.add(new BeanDefinitionHolder(bd, candidateName)); } } } candidateNames = newCandidateNames; } } while (!candidates.isEmpty());
// 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); }
publicstaticbooleanisLiteConfigurationCandidate(AnnotationMetadata metadata){ // Do not consider an interface or an annotation... if (metadata.isInterface()) { returnfalse; }
// Any of the typical annotations found? for (String indicator : candidateIndicators) { if (metadata.isAnnotated(indicator)) { returntrue; } }
// Finally, let's look for @Bean methods... try { return metadata.hasAnnotatedMethods(Bean.class.getName()); } catch (Throwable ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex); } returnfalse; } }
//处理@ComponentScan注解,扫描指定包下的所有.class,这里也是一个递归解析的过程 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 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 needed for (BeanDefinitionHolder holder : scannedBeanDefinitions) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } }