目录
作为BeanDefinitionRegistryPostProcessor的扩展回调
processConfigBeanDefinitions(BeanDefinitionRegistry registry)片段一
processConfigBeanDefinitions(BeanDefinitionRegistry registry)片段二
processConfigBeanDefinitions(BeanDefinitionRegistry registry)片段三
作为BeanFactoryPostProcessor的扩展回调
文档翻译
用于对@Configuration类进行引导处理。此后处理器按优先级排序,因为在任何其他BeanFactoryPostProcessor执行之前, @Configuration类中声明的任何Bean方法都必须注册其对应的Bean定义,这一点很重要。
作为BeanDefinitionRegistryPostProcessor的扩展回调
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
。。。。。。
processConfigBeanDefinitions(registry);
}
processConfigBeanDefinitions(BeanDefinitionRegistry registry) 基于Configuration类的注册表构建和验证配置模型。分段解析如下:
processConfigBeanDefinitions(BeanDefinitionRegistry registry)片段一
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,@Component,@ComponentScan,@Import,@ImportResource,@Bean修饰。将被修饰的BeanDefinition添加到configCandidates(配置后候选者集合中)。到目前为止就只有启动类在配置后候选者集合中
//checkConfigurationClassCandidate代码片段
//被configuration修饰标记
if (isFullConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
//被其它注解修饰标记
else if (isLiteConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
processConfigBeanDefinitions(BeanDefinitionRegistry registry)片段二
// 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(表示用户定义的@Configuration类。 以“扁平化”的方式包含一组Bean方法,包括在类的祖先中定义的所有此类方法)对象的集合。此类有助于将解析Configuration类的结构的关注与基于该模型的内容注册BeanDefinition对象的关注分开。
ConfigurationClassParser#parse(Set<BeanDefinitionHolder> configCandidates)。
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
因为启动类BeanDefinition属于AnnotatedBeanDefinition,so继续parse。
ConfigurationClassParser#parse(AnnotationMetadata metadata, String beanName)
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
ConfigurationClassParser#processConfigurationClass(ConfigurationClass configClass):处理配置类
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//根据@Conditional批注确定是否应跳过某个项目。
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
//是否缓存过该configClass的key,有的话获取到value.如果该configClass有导入的其它配置类,则合并该configClass导入的其它配置和value对应的configClass导入的其它配置
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
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.
//找到明确的bean定义,可能替换了导入。让我们删除旧的,然后使用新的。
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
//从configClass找到递归找到SourceClass(一个简单的包装程序,使带注释的源类可以以统一的方式处理,而不管它们如何加载)。
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
//上一步会返回超类的sourceClass,没有为null
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
对于启动类来说,SourceClass就只是简单的包装了启动类的class。
ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass 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(
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");
}
}
processMemberClasses(configClass, sourceClass):首先递归处理任何成员(嵌套)类。简单理解:查找该sourceClass的内部类(除去父类的),判断该内部类是否为配置类的候选者,如果是则优先处理这些配置类。处理时调用上述ConfigurationClassParser#processConfigurationClass(ConfigurationClass configClass)处理配置类方法。小结:相当于是先处理完当前配置类所有内部类是配置类的,在处理当前配置类。
ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) 片段二
// 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
//检查扫描的定义集是否有其他配置类,并在需要时递归解析(若是配置类候选者,则parse这些配置类,这就是该方法会多次调用的其中一个原因)
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(AnnotationAttributes componentScan, final String declaringClass):创建ClassPathBeanDefinitionScanner,将@ComponentScan对应的值初始化到这个扫描器上。同时会获取要扫描的basePackages。当@ComponentScan属性basePackages和basePackageClasses对应的包名,如果都为空则使用declaringClass对应的包名作为添加到basePackages。
ClassPathBeanDefinitionScanner#doScan(String... basePackages):在指定的基本程序包中执行扫描,返回已注册的bean定义。此方法不注册一个注解配置处理器而是让这件事给调用者。
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
//扫描类路径以查找候选组件。
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
//对beanDefinition进行设置,注册
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
findCandidateComponents(basePackage):扫描类路径以查找候选组件。具体扫描为父类的如下方法:
ClassPathScanningCandidateComponentProvider#scanCandidateComponents(String basePackage)
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
- 获取basePackage下的所有资源。通过Ant样式的PathMatcher查找与给定位置模式匹配的所有资源。 支持jar文件和zip文件以及文件系统中的资源。
- 遍历所有的resources,将resource包装成SimpleMetadataReader,SimpleMetadataReader包含读取resource注解元数据的AnnotationMetadataReadingVisitor:ASM类访问者,用于查找类名称和实现的类型以及在类上定义的注释,并通过AnnotationMetadata接口将其公开。
- 判断metadataReader是否满足条件: isCandidateComponent(MetadataReader metadataReader) 确定给定的类是否不匹配任何排除过滤器并且是否匹配至少一个包含过滤器。
- 若第3步满足则生成一个ScannedGenericBeanDefinition类型的BeanDefinition,接着判断该BeanDefinition是否满足条件:isCandidateComponent(AnnotatedBeanDefinition beanDefinition) 确定给定的bean定义是否符合候选条件。默认实现检查该类是否不是接口,并且不依赖于封闭的类。该方法可以在子类中覆盖。若满足则添加到候选者集合中
ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) 片段三
// 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);
}
}
getImports(SourceClass sourceClass):考虑所有元注释,返回@Import类。就是递归查找该sourceClass注解的注解是否有@Import,有的话将对应的值转换成String然后包装成SourceClass返回。
processImports(ConfigurationClass configClass, SourceClass currentSourceClass,Collection<SourceClass> importCandidates, boolean checkForCircularImports):处理上一步返回的数据。按照候选类是一个ImportSelector->委托给它以确定导入、候选类是一个ImportBeanDefinitionRegistrar->委托给它注册其他bean定义、候选类不是ImportSelector或ImportBeanDefinitionRegistrar->将其作为@Configuration类处理。
例如:mybatis的@MapperScan。可以看到有@Import,值为MapperScannerRegistrar,实现了ImportBeanDefinitionRegistrar接口,就会在这里处理,这里仅仅是将MapperScannerRegistrar实例化,然后存储到对应的ConfigurationClass中的Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars中。后续会处理该ConfigurationClass的importBeanDefinitionRegistrars这个map。
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar
ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) 片段四
// Process individual @Bean methods
//处理@Bean方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
- retrieveBeanMethodMetadata:检索所有@Bean方法的元数据。可以看出beanMethods有4个值,每一个中的methodMetadataSet值为这4个值。
- 然后将这些beanMethod对应的MethodMetadata包装成BeanMethod(表示一个标有@Bean批注的@Configuration类方法。)添加到该configClass中
ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) 片段五
// Process default methods on interfaces
//递归查找sourceClass所有接口上被@Bean修饰的方法添加到configClass的BeanMethod中
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;
processConfigBeanDefinitions(BeanDefinitionRegistry registry)片段三
//验证每个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);
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());
ConfigurationClassBeanDefinitionReader:读取给定的完全填充的ConfigurationClass实例集,并根据其内容在给定的BeanDefinitionRegistry注册Bean定义。此类是根据BeanDefinitionReader层次结构建模的,但是由于一组配置类不是Resource ,因此未实现/扩展其任何构件。
ConfigurationClassBeanDefinitionReader#loadBeanDefinitions(Set<ConfigurationClass> configurationModel):读取configurationModel ,根据其内容在注册表中注册Bean定义。该方法循环调用下面方法。
ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator):读特定的ConfigurationClass ,为类本身及其所有Bean方法注册Bean定义。同时该方法会处理该configClass收集到的ImportBeanDefinitionRegistrar,调用其registerBeanDefinitions方法注册beanDefinition。mybatis的MapperScannerRegistrar就会在这里处理。
剩余代码简单解析: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。