死磕Spring之IoC篇 - BeanDefinition 的解析过程(面向注解) (2)

调用父类的 setResourceLoader(@Nullable ResourceLoader resourceLoader) 方法,设置资源加载对象并尝试加载出 CandidateComponentsIndex 对象,方法如下:

@Override public void setResourceLoader(@Nullable ResourceLoader resourceLoader) { this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader); // 获取所有 `META-INF/spring.components` 文件中的内容 this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader()); }

这里有个关键的步骤,加载出 CandidateComponentsIndex 对象,尝试去获取所有 META-INF/spring.components 文件中的内容,后续进行分析

1. scan 方法

scan(String... basePackages) 方法,扫描出包路径下符合条件 BeanDefinition 并注册,方法如下:

public int scan(String... basePackages) { // <1> 获取扫描前的 BeanDefinition 数量 int beanCountAtScanStart = this.registry.getBeanDefinitionCount(); // <2> 进行扫描,将过滤出来的所有的 .class 文件生成对应的 BeanDefinition 并注册 doScan(basePackages); // Register annotation config processors, if necessary. // <3> 如果 `includeAnnotationConfig` 为 `true`(默认),则注册几个关于注解的 PostProcessor 处理器(关键) // 在其他地方也会注册,内部会进行判断,已注册的处理器不会再注册 if (this.includeAnnotationConfig) { AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } // <4> 返回本次扫描注册的 BeanDefinition 数量 return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart); }

过程如下:

获取扫描前的 BeanDefinition 数量

进行扫描,将过滤出来的所有的 .class 文件生成对应的 BeanDefinition 并注册,调用 doScan(String... basePackages) 方法

如果 includeAnnotationConfig 为 true(默认),则注册几个关于注解的 PostProcessor 处理器(关键),在其他地方也会注册,内部会进行判断,已注册的处理器不会再注册,记住这个 AnnotationConfigUtils

返回本次扫描注册的 BeanDefinition 数量

2. doScan 方法

doScan(String... basePackages) 方法,扫描出包路径下符合条件 BeanDefinition 并注册,方法如下:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); // <1> 定义个 Set 集合 `beanDefinitions`,用于保存本次扫描成功注册的 BeanDefinition 们 Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); for (String basePackage : basePackages) { // 遍历需要扫描的包名 // <2> 【核心】扫描包路径,通过 ASM(Java 字节码的操作和分析框架)解析出所有符合条件的 BeanDefinition Set<BeanDefinition> candidates = findCandidateComponents(basePackage); // <3> 对第 `2` 步解析出来的 BeanDefinition 依次处理,并注册 for (BeanDefinition candidate : candidates) { // <3.1> 解析出 @Scope 注解的元信息并设置 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); // <3.2> 获取或者生成一个的名称 `beanName` String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); // <3.3> 设置相关属性的默认值 if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } // <3.4> 根据这个类的相关注解设置属性值(存在则会覆盖默认值) if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } // <3.5> 检查 beanName 是否已存在,已存在但是不兼容则会抛出异常 if (checkCandidate(beanName, candidate)) { // <3.6> 将 BeanDefinition 封装成 BeanDefinitionHolder 对象,这里多了一个 `beanName` BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); // <3.7> 如果代理模式是 `TARGET_CLASS`,则再创建一个 BeanDefinition 代理对象(重新设置了相关属性),原始 BeanDefinition 已注册 definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); // <3.8> 添加至 `beanDefinitions` 集合 beanDefinitions.add(definitionHolder); // <3.9> 注册该 BeanDefinition registerBeanDefinition(definitionHolder, this.registry); } } } // <4> 返回 `beanDefinitions`(已注册的 BeanDefinition 集合) return beanDefinitions; }

过程如下:

定义个 Set 集合 beanDefinitions,用于保存本次扫描成功注册的 BeanDefinition 们

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zywzdd.html