目录
作为BeanDefinitionRegistryPostProcessor的扩展回调
processConfigBeanDefinitions(BeanDefinitionRegistry registry)片段一 :过滤出是配置类的beanName
processConfigBeanDefinitions(BeanDefinitionRegistry registry)片段二:使用ConfigurationClassParser解析候选的配置类
ConfigurationClassParser#doProcessConfigurationClass:文档翻译
processConfigBeanDefinitions(BeanDefinitionRegistry registry)片段四:解析可能被遗漏的潜在的配置类
作为BeanFactoryPostProcessor的扩展回调
文档翻译
用于对@Configuration类进行引导处理。此后处理器按优先级排序,因为在任何其他BeanFactoryPostProcessor执行之前, @Configuration类中声明的任何Bean方法都必须注册其对应的Bean定义,这一点很重要。
SourceClass
简单的包装器,允许以统一的方式处理带注释的源类,而不管它们是如何加载的。
ConfigurationClass
表示用户定义的@Configuration类。
以“扁平化”方式包含一组Bean方法,包括在类的祖先中定义的所有此类方法
作为BeanDefinitionRegistryPostProcessor的扩展回调
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
...
processConfigBeanDefinitions(registry);
}
processConfigBeanDefinitions(BeanDefinitionRegistry registry) 处理配置类型的bean定义。分段解析如下:
processConfigBeanDefinitions(BeanDefinitionRegistry registry)片段一 :过滤出是配置类的beanName
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
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));
}
}
checkConfigurationClassCandidate:检查给定的bean定义是否是配置类。分为两种情况:
- 类被
@Configuration修饰 (
Full模式) 类被@Component,@ComponentScan,@Import,@ImportResource修饰,或类上不含有这些注解,但是方法被@Bean修饰。(
Lite(精简)模式)。
到目前为止就只有启动类在配置后候选者集合中,有其它的也不用管,处理方式都是一样的。
processConfigBeanDefinitions(BeanDefinitionRegistry registry)片段二:使用ConfigurationClassParser解析候选的配置类
// Parse each @Configuration class
ConfigurationClassParser 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());
do {
parser.parse(candidates);
ConfigurationClassParser文档翻译
解析Configuration类定义,填充ConfigurationClass类对象的集合(解析单个配置类可能会产生任意数量的配置类对象,因为一个配置类可以使用Import注释导入另一个配置类)。此类有助于将【解析 Configuration 类的结构的关注点】与【基于模型内容注册 BeanDefinition 对象的关注点】分开。
ConfigurationClassParser#parse(Set<BeanDefinitionHolder> configCandidates)。因为启动类BeanDefinition属于AnnotatedBeanDefinition,so继续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
else
}
}
this.deferredImportSelectorHandler.process();
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
processConfigurationClass(ConfigurationClass configClass):处理配置类
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//1
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
//2
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
return;
}
else {
//找到明确的bean定义,可能替换了导入。让我们删除旧的,然后使用新的。
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
//3
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
//4
this.configurationClasses.put(configClass, configClass);
}
- //1 根据@Conditional批注确定是否应跳过。
- //2 是否缓存过该configClass的key,有的话获取到之前的配置类。.如果该configClass是被其它配置类导入的,则合并该两者被其它配置类导入的配置类。
- //3 递归处理配置类及其超类层次结构。对于启动类来说,SourceClass就只是简单的包装了启动类的class。
先讲下//2出被导入的含义。比如下面代码。B和C都被A导入。即内部配置类C和@Import修饰的类B都算作被主类A导入。B和C作为ConfigurationClass被解析时,内部都会维护Set<ConfigurationClass> importedBy这样一个成员变量,即我是被谁导入的,值都为A对应的ConfigurationClass。
@Import(B.class)
@Configuration
public class A{
@Configuration
public static class C{}
}
从//4处代码可以看出configurationClasses(map结构)键和值是一样的,那么/如果existingClass 不为空,则existingClass 和configClass对应的内存地址是一样的。那为啥会有下面这样的代码呢?这不是多次一举吗?
if (configClass.isImported()) {
if (existingClass.isImported()) {
其实内存地址是不一样的。看一看configClass的equals方法就知道,这个configClass不一定存在于该map中。下面举例说明什么情况下会发生这种情况。DispatcherServletAutoConfiguration还有其它内部类,这里只以这两个说明。(看完后面的再看这块,不然。。。当然熟悉下面流程的可以直接看)。
DispatcherServletAutoConfiguration是spring内部的一个自动配置类。要知道spring是先会判断是否有内部配置类的,有的话先解析。还有就是也会先解析@Import对应的配置类。获取内部类调用class如下方法,数组顺序和定义相反。开始分析:
Class<?>[] declaredClasses = sourceClass.getDeclaredClasses();
- parse DispatcherServletAutoConfiguration 发现有内部类,于是转头先解析内部类
- 先解析DispatcherServletRegistrationConfiguration,发现@Import(DispatcherServletConfiguration.class),于是转头先解析DispatcherServletConfiguration
- DispatcherServletConfiguration解析完丢入configurationClasses(map结构)中。DispatcherServletConfiguration对应的ConfigurationClass中的importedBy中存入了DispatcherServletRegistrationConfiguration
- 接着回头解析DispatcherServletRegistrationConfiguration,解析完丢入configurationClasses(map结构)中
- 要记得第二步是有两个内部类的,所以这里会再次解析DispatcherServletConfiguration,这里解析时会重新新建一个ConfigurationClass ,这个ConfigurationClass的importedBy中存入了 DispatcherServletAutoConfiguration。所以这时从configurationClasses(map结构)根据这个新建的ConfigurationClass是可以获取到之前的值的,也就是existingClass。也就是第3步中的ConfigurationClass(importedBy中存入了DispatcherServletRegistrationConfiguration),所以上面连个if都为true,然后合并两者的importedBy中的值。即最终DispatcherServletConfiguration对应的ConfigurationClass中的importedBy有两个值。
ConfigurationClassParser#doProcessConfigurationClass:文档翻译
通过从源类(sourceClass)中读取注解、成员和方法来应用处理并构建一个完整的ConfigurationClass 。当相关来源被发现时,可以多次调用此方法。
ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) 片段一:优先处理内配置类
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
}
// Process any @PropertySource annotations
//处理任何@PropertySource批注
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
......
}
processMemberClasses(configClass, sourceClass):首先递归处理任何成员(嵌套)类。简单理解:查找该sourceClass的内部类(除去父类的),判断该内部类是否为配置类的候选者,如果是则优先处理这些配置类。处理时调用上述ConfigurationClassParser#processConfigurationClass(ConfigurationClass configClass)处理配置类方法。
@PropertySource跳过。
小结:相当于是先处理完当前配置类所有内部类是配置类的,在处理当前配置类。
ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) 片段二:解析@ComponentScan并处理扫描出的潜在的配置类(包含Full模式和Lite模式的配置类)
// Process any @ComponentScan annotations
//处理任何@ComponentScan 批注,AnnotationAttributes包含注解的所有信息
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
//1
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());
}
}
}
}
- componentScanParser:ComponentScanAnnotationParser,@ComponentScan批注的解析器。
- ComponentScanAnnotationParser#parse:创建ClassPathBeanDefinitionScanner,将@ComponentScan对应的值初始化到这个扫描器上。同时会获取要扫描的basePackages。当@ComponentScan属性basePackages和basePackageClasses对应的包名如果都为空则使用declaringClass对应的包名作为添加到basePackages,对于启动类来说就是启动类所在的包名。
- //1 检查扫描出的bean定义集是否有配置类(包含Full模式和Lite模式的配置类),并在需要时递归解析(若是配置类候选者,则parse这些配置类,这就是该方法会多次调用的其中一个原因)。这里递归就可以解析自定义的配置类。递归解析:配置类中又有@ComponentScan或者后面说的@Import,无限循环。
ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) 片段三:处理@Import
// Process any @Import annotations
//处理任何@Import批注
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
//处理任何@ImportResource 批注
AnnotationAttributes 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);
}
}
@ImportResource 跳过
ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) 片段四:处理@Bean方法
// Process individual @Bean methods
//处理@Bean方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
- retrieveBeanMethodMetadata:检索所有@Bean方法的元数据。
- 然后将这些beanMethod对应的MethodMetadata包装成BeanMethod。添加到该configClass中
ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) 片段五:处理接口上的@Bean
// Process default methods on interfaces
//1
processInterfaces(configClass, sourceClass);
// Process superclass, if any
//处理超类
if (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 recurse
//找到超类,返回其注释元数据并递归
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
//没有超类->处理完成
return null;
- //1:递归查找sourceClass所有接口上被@Bean修饰的方法添加到configClass的BeanMethod中。类似下面这样的,也是可以的。
public interface InterfaceBean { @Bean default BeanDd BeanDd(){return new BeanDd();} }
processConfigBeanDefinitions(BeanDefinitionRegistry registry)片段三:注册之前收集到ConfigurationClass中的@Bean,ImportBeanDefinitionRegistrar类型,@Import相关的BeanDefinition
//验证每个ConfigurationClass对象。
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());
}
this.reader.loadBeanDefinitions(configClasses);
- ConfigurationClassBeanDefinitionReader:读取给定的完全填充的ConfigurationClass实例集,并根据其内容在给定的BeanDefinitionRegistry注册Bean定义。
- loadBeanDefinitions(Set<ConfigurationClass> ):循环读ConfigurationClass ,为类本身及其所有Bean方法注册Bean定义。同时该方法会处理该configClass收集到的ImportBeanDefinitionRegistrar,调用其registerBeanDefinitions方法注册beanDefinition。
processConfigBeanDefinitions(BeanDefinitionRegistry registry)片段四:解析可能被遗漏的潜在的配置类
alreadyParsed.addAll(configClasses);
candidates.clear();
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());
简单解析:alreadyParsed存储已经处理过的configClass.。清空当前candidates数据,因为这是一个do while循环。判断的就是candidates是否为空。然后从所有的BeanDefinition中获取到没有被解析过configClass的且满足配置类继续do while循环。防止遗漏。例如某个配置类没在扫描的包下,但是呢该类在某一个类中被主动注册了,那么这里就可以解析该配置类。
作为BeanFactoryPostProcessor的扩展回调
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
enhanceConfigurationClasses:对被@Configuration修饰的BeanDefinition进行增强处理。增强处理类为ConfigurationClassEnhancer:通过生成一个CGLIB子类来增强Configuration类,该子类与Spring容器进行交互,以遵守@Bean方法的bean作用域语义。 每个此类@Bean方法都将在生成的子类中被覆盖,仅当容器实际请求构造新实例时才委托给实际的@Bean方法实现。 否则,对此类@Bean方法的调用将作为对容器的引用, @Bean名称获取相应的bean。