前面介绍了scanner可以扫描某个包路径下的所有bean,我们最常用的也是通过ComponentScan指定包路径去扫描,在SpringBoot中也是如此,本文将介绍spring扫描的逻辑
知道了ComponentScan的作用,那么spring什么时候开始解析ComponentScan去扫描bean呢
这个时候就要知道spring的其中一个生命周期 BeanDefinitionRegistryPostProcessor
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
该生命周期可以说是最早的一个,还在BeanFactoryPostProcessor#postProcessBeanFactory之前执行
从接口提供的方法就很明确,可以自己去注册一些bean
那么在该接口实现类里面就可以将最开始注册的AppConfig类拿出来,确定有ComponentScan注解,就可以拿到路径去扫描,最终注册bean
ConfigurationClassPostProcessor 实现了 BeanDefinitionRegistryPostProcessor
在spring中通过该类进行配置类的解析,并且注册bean,只不过在spring中,标名是一个配置类的注解多种多样 ComponentScan 也只是其中一个
本文主要讲 ComponentScan 其它配置类后面讲
注册
源码链路
AnnotationConfigApplicationContext(Class>… componentClasses) # 进入this()
AnnotationConfigApplicationContext()
AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry)
AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment)
AnnotationConfigUtils#registerAnnotationConfigProcessors(BeanDefinitionRegistry registry)
AnnotationConfigUtils#registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source)
可以看到这么一行 注册ConfigurationClassPostProcessor
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
获取注册的ConfigurationClassPostProcessor
进入refresh方案,spring最重要的一个方法,整个生命周期都在这
会看到如下代码
// 获取BeanDefinitionRegistryPostProcessor,一般来说就只有一个 ConfigurationClassPostProcessor
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 排个序
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 执行 BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
// 扫描完之后还有可能生成BeanFactoryPostProcessor
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
// 过滤之前执行过的BeanFactoryPostProcessor
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
以上就是获取 ConfigurationClassPostProcessor 到执行它的 postProcessBeanDefinitionRegistry方法的
逻辑,通过beanFactory.getBeanNamesForType 获取 BeanDefinitionRegistryPostProcessor
将获取到的BeanDefinitionRegistryPostProcessor 排个序,通过@Order注解或者@javax.annotation.Priority注解确定排序
遍历执行postProcessBeanDefinitionRegistry方法
那么在ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry又是怎么解析ComponentScan注册bean呢
public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
// getFactoryMethodName表示是@Bean方式注入的bean,这种不作为配置类
String className = beanDef.getBeanClassName();
// 注解信息,通过MetadataReader获取(ASM技术) 并没有加载类
AnnotationMetadata metadata;
// 如果AnnotatedBeanDefinition,则直接取AnnotationMetadata
if (beanDef instanceof AnnotatedBeanDefinition && className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
}
// 如果是AbstractBeanDefinition,则解析beanClass得到AnnotationMetadata
else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
metadata = AnnotationMetadata.introspect(beanClass);
}
else {
// ASM技术,这里其实也是spring提供的一个工具,我们也可以使用,后续文章介绍
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
metadata = metadataReader.getAnnotationMetadata();
}
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
// 存在@Configuration,并且proxyBeanMethods不为false,就是配置类 配置类型为Full
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
// 设置属性configurationClass,表示是配置类
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
// 存在@Configuration,并且proxyBeanMethods为false时,也是配置类配置类型为lite
// 不存在@Configuration,存在@Component、@ComponentScan、@Import、@ImportResource中的某一个,也是配置类 配置类型为lite
// 有@Bean标注的方法也是配置类
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
// It's a full or lite configuration candidate... Let's determine the order value, if any.
Integer order = getOrder(metadata);
if (order != null) {
// 配置类也可以排序,使用 Order注解
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}
private static final Set<String> candidateIndicators = new HashSet<>(8);
static {
candidateIndicators.add(Component.class.getName());
candidateIndicators.add(ComponentScan.class.getName());
candidateIndicators.add(Import.class.getName());
candidateIndicators.add(ImportResource.class.getName());
}
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
// 接口不管
if (metadata.isInterface()) {
return false;
}
// 只要存在@Component、@ComponentScan、@Import、@ImportResource四个中的一个,就是lite配置类
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}
// Finally, let's look for @Bean methods...
// 只要存在@Bean注解了的方法,就是lite配置类
return hasBeanMethods(metadata);
}
根据上面的代码逻辑分析,拥有@Configuration @Component、@ComponentScan、@Import、@ImportResource
或者方法有@Bean注解,那么就是一个配置类,继续后面代码分析
其它配置类先不看,那么会看到会看到如下代码
// 查看是否有ComponentScan注解
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());
}
}
}
}
查看该Bean的有没有ComponentScans或者ComponentScan注解,如果有那么使用ComponentScanAnnotationParser解析
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
// bean的名字生成器,默认是首字母小写的类名,可以自己定义其它规则,比如类的全限定名
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
// 默认为AnnotationBeanNameGenerator
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
BeanUtils.instantiateClass(generatorClass));
// 默认就是扫描包下面的class文件
scanner.setResourcePattern(componentScan.getString("resourcePattern"));
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
Set<String> basePackages = new LinkedHashSet<>();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
// 排除掉自己
return declaringClass.equals(className);
}
});
// 开始扫描,注册bean
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
以上就是如何解析ComponentScan的逻辑,解析完后,开始扫描,进行BeanDefinition注册,注意是BeanDefinition注册,还不是实例化bean
最终存放在 beanDefinitionMap beanDefinitionNames 记住这两个属性,特别重要
private final Map
private volatile List beanDefinitionNames = new ArrayList<>(256);
以上就是通过ComponentScan注解注册Bean的逻辑了,其它配置类以及实例化bean的逻辑后面文章在介绍
欢迎关注,学习不迷路!