大家都知道 Spring扫描 启动的时候 会扫描我们的项目 把我们的定义的Bean 给加到容器中去 那么这个扫描是怎么个顺序的的呢?
首先Spring启动的时候 会往自己的容器中 加一个自己的实现了
BeanDefinitionRegistryPostProcessor
的接口的处理器
org.springframework.context.annotation.ConfigurationClassPostProcessor
正是由这个后置处理器 扫描项目 加入Bean 到我们的容器 那么扫描总有个顺序 那么具体时怎么扫描法呢?
spring 那么多注解 例如:
@PropertySource
@ComponentScan
@Configuration
@import
@Bean
@Component
。。。。
带有这些注解的类 可能会一直导入新的类 新的类可能又会导出其他的bean 所以很明显 扫描的时候 肯定是要递归扫描的
Spring 具体扫描的类是:org.springframework.context.annotation.ConfigurationClassParser
下面就是扫描的具体 逻辑:
// 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;
}
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
Collection memberClasses = sourceClass.getMemberClasses();
if (!memberClasses.isEmpty()) {
List candidates = new ArrayList<>(memberClasses.size());
for (SourceClass memberClass : memberClasses) {
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getmetadata()) &&
!memberClass.getmetadata().getClassName().equals(configClass.getmetadata().getClassName())) {
candidates.add(memberClass);
}
}
OrderComparator.sort(candidates);
for (SourceClass candidate : candidates) {
if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularimportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
processConfigurationClass(candidate.asConfigClass(configClass));
}
finally {
this.importStack.pop();
}
}
}
}
}
我总结一下:
首先从启动类开始:
0 将启动类 作为第一个扫描源
1 处理 @PropertySource 注解 若有 则相应的处理
2 处理 @ComponentScan
在处理这个注解的过程 会有很多类被扫描出来 这些类 其中如果有@Configuration 那么这个类 那么将会 如启动类当作扫描源 递归扫描 从头开始扫描
3 处理 @import 3.1 push importStack 栈 3.2 如果import的类是 实现了 importSelector (特殊处理 : 如果实现的是 DeferredSelector(延迟导入 springBoot 里面的自动配置 的处理类 就是实现的它 因为它能保证我们自动配置导入的时候 容器的其他bean 已经进入容器了 这样我们的OnMIss什么的注解才能起到作用) 那么将这个收集到一个 集合里面 后面容器最终再处理这些类 ) 不是的话 就没有特殊处理 或者
importBeanDefinitionRegistrar 那么递归处理 否则 将其作为Configuration 再递归扫描一次
private void processimports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection importCandidates, 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) {
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));
}
}
}
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();
}
}
}
4 处理 @importResource 5 处理 @Bean 6 其他后置处理



