上一篇Spring源码(一)——Bean生命周期源码解读文章,讲了下Bean的生命周期以及ApplicationContext构造方法的大致逻辑,其中最核心的是refresh方法,但是里面有些方法没有细说。比如invokeBeanFactoryPostProcessors(beanFactory),registerBeanPostProcessors(beanFactory),
finishBeanFactoryInitialization(beanFactory)
这三个方法 是refresh 中想当重要的方法。今天我们就详细看看invokeBeanFactoryPostProcessors这个方法
这个方法直译过来就是:执行BeanFactory的后置处理器,注意这个后置处理器是Spring自带的后置处理器,而不是程序员编写的PostProcessor后置处理器。我们上一篇文章中说了,在AnnotationConfigApplicationContext的构造方法中,Spring去创建了一个AnnotationBeanDefinition读取器(AnnotationBeanDefinitionReader),这个读取器的构造方法中会向BeanFactory中注册spring自带的BeanPostProcessor。
在执行这些BeanPostProcessor中,spring会去解析你传入的配置类以及扫码方法。
解析配置类我们下钻看看invokeBeanFactoryPostProcessors这个方法。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//主要就是这个方法。getBeanFactoryPostProcessors这个方法是获取容器中的已经存在的BeanFactoryPostProcessor对象。
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
//这块忽略,不重要
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
继续想下钻 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法,能看到这样一段代码。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//.....省略的代码
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set candidates = new linkedHashSet<>(configCandidates);
Set alreadyParsed = new HashSet<>(configCandidates.size());
do {
parser.parse(candidates);
//.....省略的代码
}while (!candidates.isEmpty());
//.....省略的代码
}
这里面能看到 parser.parse(candidates) 这样一个解析配置类的方法。
我们继续下钻看看parse 是什么逻辑。
public void parse(SetconfigCandidates) { this.deferredimportSelectors = new linkedList<>(); for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { 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); } } processDeferredimportSelectors(); }
这段代码能看出来,这个方法是遍历所有程序员在AnontationConfigApplicationContext启动时,传入的配置类。然后根据配置类的BeanDefinition的类型判断走那个parse方法。由于我们的SysConfig.class 是一个注解配置类,所以我们会进入 processConfigurationClass方法。
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//.....省略的代码
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
然后下钻doProcessConfigurationClass这个方法。
@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getmetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getmetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
Set 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 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());
}
}
}
}
// Process any @import annotations
processimports(configClass, sourceClass, getimports(sourceClass), true);
// Process any @importResource annotations
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);
}
}
// Process individual @Bean methods
Set beanMethods = retrieveBeanMethodmetadata(sourceClass);
for (Methodmetadata methodmetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodmetadata, configClass));
}
// Process default methods on interfaces
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;
}
我们一段一段看看这个方法
processMemberClasses(configClass, sourceClass);
这个方法查看配置类的内部类是否是配置类 如果是再次调用processConfigurationClass。也就是遍历判断配置类。
下一段
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getmetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getmetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
这个方法是获取配置类上的@PropertySources 注解 ,将propertis文件的键值对加载到容器的环境中。
在下一段 重点来了!!!!!:
// Process any @ComponentScan annotations SetcomponentScans = 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 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()); } } } }
注意:
Set componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getmetadata(), ComponentScans.class, ComponentScan.class);
ComponentScan.class 这个类是不是非常熟悉。是不是就是我们的扫描包路径的一个注解?@ComponentScan({“com.service”,“com.Aspect”}) 是不是就是这个?。
spring去遍历@Component这个注解配置的扫描路径,去执行下面这个扫描的方法(扫描的具体类容后面在说)。
SetscannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getmetadata().getClassName());
这个方法里面就会去扫描配置的路径,扫描所有添加了@Component注解的类,将类信息封装成BeanDefinition中。这里是不会创建Bean对象的,只是存储类信息,到后面将所有类信息一起实例化。
下一段:
// 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());
}
}
这个方法就是遍历扫描出来的所有@Component注释的类的BeanDefinition,将这个BeanDefinition当作配置类,用迭代的方式继续执行parse方法。继续解析。
继续看下一段
// Process any @import annotations processimports(configClass, sourceClass, getimports(sourceClass), true);
这个方法是处理所有@import注解。进入方法
private void processimports(ConfigurationClass configClass, SourceClass currentSourceClass, CollectionimportCandidates, boolean checkForCircularimports) { //.....省略的代码 for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(importSelector.class)) { // Candidate class is an importSelector -> delegate to it to determine imports Class> candidateClass = candidate.loadClass(); importSelector selector = BeanUtils.instantiateClass(candidateClass, importSelector.class); ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); if (this.deferredimportSelectors != null && selector instanceof DeferredimportSelector) { this.deferredimportSelectors.add( new DeferredimportSelectorHolder(configClass, (DeferredimportSelector) selector)); } else { String[] importClassNames = selector.selectimports(currentSourceClass.getmetadata()); Collection importSourceClasses = asSourceClasses(importClassNames); processimports(configClass, currentSourceClass, importSourceClasses, false); } } else if (candidate.isAssignable(importBeanDefinitionRegistrar.class)) { // Candidate class is an importBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class> candidateClass = candidate.loadClass(); importBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, importBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods( registrar, this.environment, this.resourceLoader, this.registry); configClass.addimportBeanDefinitionRegistrar(registrar, currentSourceClass.getmetadata()); } else { // Candidate class not an importSelector or importBeanDefinitionRegistrar -> // process it as an @Configuration class this.importStack.registerimport( currentSourceClass.getmetadata(), candidate.getmetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); } } //.....省略的代码 }
这个方法也会去判断导入的类是不是配置类
- 如果导入的类实现了importSelector类型
a. 如果是DeferredimportSelector类型,表示推迟的importSelector,它会在当前配置类所属的批次中所有配置类都解析完了之后执行
b. 如果是普通的importSelector类型,迭代的方法执行processimports方法。 - 如果导入的类是importBeanDefinitionRegistrar类型,回将importBeanDefinitionRegistrar配置到configClass中。
- 如果都不是 就是一个普通的配置类,调用processConfigurationClass 继续解析这个新配置类。
继续下一段代码:
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.class注解。将导入的源文件路径添加到配置类的importedResource属性上。 注意这个类不会将导入的当作配置类。
再下一段
SetbeanMethods = retrieveBeanMethodmetadata(sourceClass); for (Methodmetadata methodmetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodmetadata, configClass)); }
retrieveBeanMethodmetadata方法的类容如下:
private SetretrieveBeanMethodmetadata(SourceClass sourceClass) { Annotationmetadata original = sourceClass.getmetadata(); Set beanMethods = original.getAnnotatedMethods(Bean.class.getName()); if (beanMethods.size() > 1 && original instanceof StandardAnnotationmetadata) { // Try reading the class file via ASM for deterministic declaration order... // Unfortunately, the JVM's standard reflection returns methods in arbitrary // order, even between different runs of the same application on the same JVM. try { Annotationmetadata asm = this.metadataReaderFactory.getmetadataReader(original.getClassName()).getAnnotationmetadata(); Set asmMethods = asm.getAnnotatedMethods(Bean.class.getName()); if (asmMethods.size() >= beanMethods.size()) { Set selectedMethods = new linkedHashSet<>(asmMethods.size()); for (Methodmetadata asmMethod : asmMethods) { for (Methodmetadata beanMethod : beanMethods) { if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) { selectedMethods.add(beanMethod); break; } } } if (selectedMethods.size() == beanMethods.size()) { // All reflection-detected methods found in ASM method set -> proceed beanMethods = selectedMethods; } } } catch (IOException ex) { logger.debug("Failed to read class file via ASM for determining @Bean method order", ex); // No worries, let's continue with the reflection metadata we started with... } } return beanMethods; }
这个方法就是将配置类以及它的父类的所有使用了@Bean注解的方法。然后将这些方法添加到配置的的一个Method中
然后在下一个方法:
// Process default methods on interfaces processInterfaces(configClass, sourceClass);
这个方法与上一段代码是类似的,上一段是将父类中被@Bean注解的方法封装假如到配置类的BeanMethod中,这一段就是将配置类实现的接口中,被@Bean注解的方法封装假如到配置类的BeanMethod中。
最后一段代码:
// 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();
}
}
这段代码很简单,判断当前配置类是否有父类,如果有将这个父类返回,然后继续执行这个doProcessConfigurationClass方法解析这个父类。
解析配置类总结
- 判断配置类的内部类是不是配置类,是就解析内部类。
- 判断是否有@ComponentScan,有的话扫描所有@Component,@Name,@ManagedBean。如果是@Component注解的类会将这个类当作一个配置类进行解析。
- 配置类上是否有@imports,获取导入的类。
a. 如果导入的类是importSelector.class类型,并且是DeferredimportSelector.class加入延迟解析数据。如果只是一个importSelector.继续解析这个类
b.如果当前类是importBeanDefinitionRegistrar类型,将importBeanDefinitionRegistrar假如到配置类中。
c. 就是一个普通类型,当成新的配置类解析。 - 判断配置类上是否有@importResource注解,将注解执行的文件加载到配置文件中。
- 获取配置类中所有@Bean注解的方法,添加到配置类的beanMethod中。
- 判断配置类的接口类,将其中的@Bean注解的方法添加到配置类中。
- 判断配置类是否有父类,如果有将父类当成一个新的配置类,迭代方式解析。
上面就是我们的spring解析配置类的思路。
下面我们继续详细的看看@ComponentScan的扫描方法。
protected SetdoScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set beanDefinitions = new linkedHashSet<>(); for (String basePackage : basePackages) { Set candidates = findCandidateComponents(basePackage); 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继续下钻,能看到scanCandidateComponents这样一个方法。
private SetscanCandidateComponents(String basePackage) { Set 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.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); } } } else { if (traceEnabled) { logger.trace("Ignored because not matching any filter: " + resource); } } } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to read candidate component class: " + resource, ex); } } else { if (traceEnabled) { logger.trace("Ignored because not readable: " + resource); } } } } catch (IOException ex) { throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex); } return candidates; }
这个方法传入了一个basePackages的参数 ,这个就是扫描的路径,spring首先会将要扫描的路径进行拼接,classpath*:com/service*.class 这种类型,如下代码。
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolvebasePackage(basePackage) + '/' + this.resourcePattern;
获取这个路径下所有所有的class文件。
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
遍历这些文件判断是否能需要封装成BeanDefinition中,加入到容器中。
metadataReader metadataReader = getmetadataReaderFactory().getmetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
}
这个方法会判断是否使用这个class:isCandidateComponent(metadataReader metadataReader),这个允许@Component能注册,另外还有@ManagedBean (javax.annotation.ManagedBean),@Named(javax.inject.Named)这些注解的类生成BeanDefinition.
然后在通过isCandidateComponent(AnnotatedBeanDefinition beanDefinition),判断是否假如配置类中。
我们在来看看默认生成BeanName的方法,
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isUpperCase(name.charAt(0))){
return name;
}
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
这个方法中 能看出 如果class的类名前两个数字是大写,则直接返回class名称,否则返回首字母小写的类名称做BeanName,当然如果设置了名称肯定用设置的名称。
然后调用AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);方法给BeanDefinition设置初始值。
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
最后将BeanDefinition注册到容器中去
registerBeanDefinition(definitionHolder, this.registry);
扫描的流程图
好了以上就是这个文章的所有内容了。
Thankfulness is the quickest path to joy.
懂得感恩的人,更容易收获快乐。
;————摘自有道翻译



