我们要找出所有符合条件的业务Bean,首先我们需要知道在Spring中什么样的Bean是符合条件的,是需要容器来管理的:
- 使用组件标注注解的Bean(@Controller、@Service、@Repository、@Component),一般项目里面使用。
- 使用@Bean注解标准的方法,一般导入第三方组件的时候使用。
- 使用@Import注解导入的Bean,一般快速导入一批组件时使用。
doProcessConfigurationClass 配置类的解析过程
调用链路:
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)
源码:
// 解析配置类将业务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注解,解析配置文件,将配置项加载到环境变量里面
- 处理@ComponentScan注解,将所有符合条件Bean的BeanDefinition注册到容器
- 处理@Import注解
- 处理@ImportResource注解
- 处理@Bean方法
- 处理接口的默认方法
- 处理父类
处理@ComponentScan注解
我们这里主要介绍下@ComponentScan注解的处理过程,最后主要的处理方法是ClassPathBeanDefinitionScanner#doScan()方法。
调用链路:
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 执行包扫描
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) {
// 根据包路径找到需要加载到容器的业务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;
}
// 根据包路径找到需要加载到容器的业务Bean
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
try {
// 根据包路径找到需要加载到容器class文件
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
// 根据资源加载器加载所有在对应包路径下的class文件到内存
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 {
// 执行excludeFilters
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return false;
}
}
// 执行includeFilters
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return isConditionMatch(metadataReader);
}
}
return false;
}
findCandidateComponents方法最终会调用AnnotationMetadataReadingVisitor类的hasAnnotation和hasMetaAnnotation方法来判断是否是@Component组件。
调用链路:
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 {
...
// 判断是否是业务Bean
@Override
public boolean hasAnnotation(String annotationName) {
return this.annotationSet.contains(annotationName);
}
// 判断是否是业务Bean
@Override
public boolean hasMetaAnnotation(String metaAnnotationType) {
// 如果业务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;
}
...
}
执行流程:
- 根据@ComponentScan注解配置的包范围找到所有符合条件的class文件
- 根据资源加载器,将所有的class文件加载到内存
- 循环遍历class找出符合条件的@Component组件
- 执行@ComponentScan的excludeFilters
- 执行@ComponentScan的includeFilters
- 获取当前class的metaAnnotationMap,判断是否是@Component组件
- 将符合条件的class的BeanDefinition注册到容器
如果业务Bean是加的@Service注解,那么在metaAnnotationMap中将会以 org.springframework.stereotype.Service=org.springframework.stereotype.Component的形式存储, 将@Service注解映射成@Component注解。其他继承自@Component注解的处理方式也一样