我們要找出所有符合條件的業(yè)務Bean魏烫,首先我們需要知道在Spring中什么樣的Bean是符合條件的检痰,是需要容器來管理的:
- 使用組件標注注解的Bean(@Controller难咕、@Service峰弹、@Repository回怜、@Component)大年,一般項目里面使用。
- 使用@Bean注解標準的方法鹉戚,一般導入第三方組件的時候使用鲜戒。
- 使用@Import注解導入的Bean,一般快速導入一批組件時使用抹凳。
doProcessConfigurationClass 配置類的解析過程
調(diào)用鏈路:
doProcessConfigurationClass:289, ConfigurationClassParser (org.springframework.context.annotation)
processConfigurationClass:247, ConfigurationClassParser (org.springframework.context.annotation)
parse:200, ConfigurationClassParser (org.springframework.context.annotation)
parse:169, ConfigurationClassParser (org.springframework.context.annotation)
processConfigBeanDefinitions:308, ConfigurationClassPostProcessor (org.springframework.context.annotation)
postProcessBeanDefinitionRegistry:228, ConfigurationClassPostProcessor (org.springframework.context.annotation)
invokeBeanDefinitionRegistryPostProcessors:272, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:92, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:687, AbstractApplicationContext (org.springframework.context.support)
refresh:525, AbstractApplicationContext (org.springframework.context.support)
<init>:84, AnnotationConfigApplicationContext (org.springframework.context.annotation)
源碼:
// 解析配置類將業(yè)務Bean的定義BeanDefinition注冊到容器
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<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());
}
}
}
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
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<MethodMetadata> 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.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;
}
從源碼我們可以看到解析配置類的完整過程:
- 使用遞歸的方式處理嵌套類
- 處理@PropertySource注解遏餐,解析配置文件,將配置項加載到環(huán)境變量里面
- 處理@ComponentScan注解赢底,將所有符合條件Bean的BeanDefinition注冊到容器
- 處理@Import注解
- 處理@ImportResource注解
- 處理@Bean方法
- 處理接口的默認方法
- 處理父類
處理@ComponentScan注解
我們這里主要介紹下@ComponentScan注解的處理過程失都,最后主要的處理方法是ClassPathBeanDefinitionScanner#doScan()方法。
調(diào)用鏈路:
doScan:270, ClassPathBeanDefinitionScanner (org.springframework.context.annotation)
parse:135, ComponentScanAnnotationParser (org.springframework.context.annotation)
doProcessConfigurationClass:289, ConfigurationClassParser (org.springframework.context.annotation)
processConfigurationClass:247, ConfigurationClassParser (org.springframework.context.annotation)
parse:200, ConfigurationClassParser (org.springframework.context.annotation)
parse:169, ConfigurationClassParser (org.springframework.context.annotation)
processConfigBeanDefinitions:308, ConfigurationClassPostProcessor (org.springframework.context.annotation)
postProcessBeanDefinitionRegistry:228, ConfigurationClassPostProcessor (org.springframework.context.annotation)
invokeBeanDefinitionRegistryPostProcessors:272, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:92, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:687, AbstractApplicationContext (org.springframework.context.support)
refresh:525, AbstractApplicationContext (org.springframework.context.support)
<init>:84, AnnotationConfigApplicationContext (org.springframework.context.annotation)
源碼:
// @ComponentScan 執(zhí)行包掃描
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
for (String basePackage : basePackages) {
// 根據(jù)包路徑找到需要加載到容器的業(yè)務Bean
Set<BeanDefinition> 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);
// 將符合條件的Bean 定義注冊到容器
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
// 根據(jù)包路徑找到需要加載到容器的業(yè)務Bean
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
try {
// 根據(jù)包路徑找到需要加載到容器class文件
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
// 根據(jù)資源加載器加載所有在對應包路徑下的class文件到內(nèi)存
Resource[] resources = this.resourcePatternResolver.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 = this.metadataReaderFactory.getMetadataReader(resource);
// 判斷是否是@Component組件
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);
}
...
return candidates;
}
// 判斷是否是@Component組件
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
// 執(zhí)行excludeFilters
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return false;
}
}
// 執(zhí)行includeFilters
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return isConditionMatch(metadataReader);
}
}
return false;
}
findCandidateComponents方法最終會調(diào)用AnnotationMetadataReadingVisitor類的hasAnnotation和hasMetaAnnotation方法來判斷是否是@Component組件幸冻。
調(diào)用鏈路:
hasMetaAnnotation:112, AnnotationMetadataReadingVisitor (org.springframework.core.type.classreading)
matchSelf:86, AnnotationTypeFilter (org.springframework.core.type.filter)
match:61, AbstractTypeHierarchyTraversingFilter (org.springframework.core.type.filter)
isCandidateComponent:354, ClassPathScanningCandidateComponentProvider (org.springframework.context.annotation)
findCandidateComponents:288, ClassPathScanningCandidateComponentProvider (org.springframework.context.annotation)
doScan:272, ClassPathBeanDefinitionScanner (org.springframework.context.annotation)
parse:135, ComponentScanAnnotationParser (org.springframework.context.annotation)
doProcessConfigurationClass:289, ConfigurationClassParser (org.springframework.context.annotation)
processConfigurationClass:247, ConfigurationClassParser (org.springframework.context.annotation)
parse:200, ConfigurationClassParser (org.springframework.context.annotation)
parse:169, ConfigurationClassParser (org.springframework.context.annotation)
processConfigBeanDefinitions:308, ConfigurationClassPostProcessor (org.springframework.context.annotation)
postProcessBeanDefinitionRegistry:228, ConfigurationClassPostProcessor (org.springframework.context.annotation)
invokeBeanDefinitionRegistryPostProcessors:272, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:92, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:687, AbstractApplicationContext (org.springframework.context.support)
refresh:525, AbstractApplicationContext (org.springframework.context.support)
<init>:84, AnnotationConfigApplicationContext (org.springframework.context.annotation)
源碼:
// 判斷是否是@Component組件
public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
...
// 判斷是否是業(yè)務Bean
@Override
public boolean hasAnnotation(String annotationName) {
return this.annotationSet.contains(annotationName);
}
// 判斷是否是業(yè)務Bean
@Override
public boolean hasMetaAnnotation(String metaAnnotationType) {
// 如果業(yè)務Bean是加的@Service注解粹庞,那么在metaAnnotationMap中將會以
// org.springframework.stereotype.Service=org.springframework.stereotype.Component的形式存儲,
// 將@Service注解映射成@Component注解洽损。其他繼承自@Component注解的處理方式也一樣
Collection<Set<String>> allMetaTypes = this.metaAnnotationMap.values();
for (Set<String> metaTypes : allMetaTypes) {
if (metaTypes.contains(metaAnnotationType)) {
return true;
}
}
return false;
}
...
}
執(zhí)行流程:
- 根據(jù)@ComponentScan注解配置的包范圍找到所有符合條件的class文件
- 根據(jù)資源加載器庞溜,將所有的class文件加載到內(nèi)存
- 循環(huán)遍歷class找出符合條件的@Component組件
- 執(zhí)行@ComponentScan的excludeFilters
- 執(zhí)行@ComponentScan的includeFilters
- 獲取當前class的metaAnnotationMap,判斷是否是@Component組件
- 將符合條件的class的BeanDefinition注冊到容器
如果業(yè)務Bean是加的@Service注解碑定,那么在metaAnnotationMap中將會以 org.springframework.stereotype.Service=org.springframework.stereotype.Component的形式存儲流码, 將@Service注解映射成@Component注解。其他繼承自@Component注解的處理方式也一樣