@ComponentScan包扫描功能实现
实现过程:
① @ComponentScan 这个注解的作用
作用自己搜索
② spring 如何解析@ComponentScan:
spring的核心模块spring-context中的package org.springframework.context.support中,有个注解解析类ComponentScanAnnotationParser。
ComponentScanAnnotationParser有个方法parse(),这个方法就是用来解析ComponentScan的,
在parse()中定义了ClassPathBeanDefinitionScanner,ClassPathBeanDefinitionScanner scanner
= new ClassPathBeanDefinitionScanner(…); scanner 是扫描器。同时parse()实现对
@ComponentScan的useDefaultFilters、scopedProxy、scopedProxy、scopeResolver、
resourcePattern,includeFilters、excludeFilters、lazyInit、basePackageClasses、basePackages等属
性的访问获取信息生成一个对象,然后给scanner.doScan()使用。
在ClassPathBeanDefinitionScanner主要两个tips:
1、ClassPathBeanDefinitionScanner构造器中的执行的父类的 registerDefaultFilters()方法,在这个方法中this.includeFilters.add(new AnnotationTypeFilter(Component.class)); 添加了带有@Component注解的类。
ClassPathBeanDefinitionScanner的doScan扫描方法中,用registerBeanDefinition(definitionHolder, this.registry)方法注册了bean, definitionHolder, bean的信息持有者,registry注册器。在registerBeanDefinition()方法中调用了BeanDefinitionReaderUtils.registerBeanDefinition()进行bean注册,而这个方法最终使用的是registry进行注册的,代码是这样: registry.registerBeanDefinition(beanName,definitionHolder.getBeanDefinition());
2、registry在哪里:
ConfigurationClassParser类的构造器中使用就是BeanDefinitionRegistry的registry,ConfigurationClassParser下文会介绍。
public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader,
BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry) {
this.metadataReaderFactory = metadataReaderFactory;
this.problemReporter = problemReporter;
this.environment = environment;
this.resourceLoader = resourceLoader;
this.registry = registry;
this.componentScanParser = new ComponentScanAnnotationParser(
environment, resourceLoader, componentScanBeanNameGenerator, registry);
this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
}
③ ConfigurationClassParser:
位置:
package org.springframework.context.annotation#ConfigurationClassParser
ConfigurationClassParser:这个类为配置类解析器。
这个类型有个方法doProcessConfigurationClass,在这个方法中定义了@ComponentScans信息,
Set componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
componentScans包含了注解@ComponentScans的各种属性,
然后调用 this.componentScanParser.parse(这个ComponentScanAnnotationParser类的方法parse)
会对各种属性进行分析并执行相应的功能。
具体代码:
// 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());
}
}
}
}
④ ConfigurationClassParser的registry来源
ConfigurationClassParser构造函数registry
spring核心模块spring-context
包package org.springframework.context.annotation
类:ConfigurationClassPostProcessor#ConfigurationClassParser
public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader,
BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry) {
this.metadataReaderFactory = metadataReaderFactory;
this.problemReporter = problemReporter;
this.environment = environment;
this.resourceLoader = resourceLoader;
this.registry = registry;
this.componentScanParser = new ComponentScanAnnotationParser(
environment, resourceLoader, componentScanBeanNameGenerator, registry);
this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
}
spring核心模块spring-context
包package org.springframework.context.annotation
类:ConfigurationClassPostProcessor#processConfigBeanDefinitions
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
**processConfigBeanDefinitions方法**
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
spring核心模块spring-context
包package org.springframework.context.support
类:PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
.tag("postProcessor", postProcessor::toString);
postProcessor.postProcessBeanDefinitionRegistry(registry);
postProcessBeanDefRegistry.end();
}
}
spring核心模块spring-context
包package org.springframework.context.support
AbstractApplicationContext#invokeBeanFactoryPostProcessors
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
调用过程:
ClassPathXmlApplicationContext实现AbstractApplicationContext
----->AbstractApplicationContext.invokeBeanFactoryPostProcessors()
----->PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()
---->ConfigurationClassPostProcessor.processConfigBeanDefinitions()
---->ConfigurationClassParser.ConfigurationClassParser()
---->ConfigurationClassParser() this.registry = registry;
---->ConfigurationClassParser.doProcessConfigurationClass()
---->doProcessConfigurationClass
------>this.componentScanParser.parse()