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

该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读

Spring 版本:5.1.14.RELEASE

开始阅读这一系列文章之前,建议先查看《深入了解 Spring IoC(面试题)》这一篇文章

该系列其他文章请查看:《死磕 Spring 之 IoC 篇 - 文章导读》

BeanDefinition 的解析过程(面向注解)

前面的几篇文章对 Spring 解析 XML 文件生成 BeanDefinition 并注册的过程进行了较为详细的分析,这种定义 Bean 的方式是面向资源(XML)的方式。面向注解定义 Bean 的方式 Spring 的处理过程又是如何进行的?本文将会分析 Spring 是如何将 @Component 注解或其派生注解 标注的 Class 类解析成 BeanDefinition(Bean 的“前身”)并注册。

在上一篇 《解析自定义标签(XML 文件)》文章中提到了处理 <context:component-scan /> 标签的过程中,底层借助于 ClassPathBeanDefinitionScanner 扫描器,去扫描指定路径下符合条件的 BeanDefinition 们,这个类就是处理 @Component 注解定义 Bean 的底层实现。关于 @ComponentScan 注解的原理也是基于这个扫描器来实现的,我们先来看看这个扫描器的处理过程。

类图

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

ClassPathBeanDefinitionScanner

org.springframework.context.annotation.ClassPathBeanDefinitionScanner,继承 ClassPathScanningCandidateComponentProvider,classpath 下 BeanDefinition 的扫描器,支持设置过滤器

默认有三个过滤器: @Component 注解的过滤器,Java EE 6 的 javax.annotation.ManagedBean 注解过滤器,JSR-330 的 javax.inject.Named 注解过滤器,这里我们重点关注第一个过滤器

构造函数 public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider { /** BeanDefinition 注册中心 DefaultListableBeanFactory */ private final BeanDefinitionRegistry registry; /** BeanDefinition 的默认配置 */ private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults(); @Nullable private String[] autowireCandidatePatterns; /** Bean 的名称生成器 */ private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator(); private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver(); /** 是否注册几个关于注解的 PostProcessor 处理器 */ private boolean includeAnnotationConfig = true; public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) { this(registry, true); } public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) { this(registry, useDefaultFilters, getOrCreateEnvironment(registry)); } public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment) { this(registry, useDefaultFilters, environment, (registry instanceof ResourceLoader ? (ResourceLoader) registry : null)); } public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, @Nullable ResourceLoader resourceLoader) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); this.registry = registry; if (useDefaultFilters) { // 注册默认的过滤器,@Component 注解的过滤器(具有层次性) registerDefaultFilters(); } setEnvironment(environment); // 设置资源加载对象,会尝试加载出 CandidateComponentsIndex 对象(保存 `META-INF/spring.components` 文件中的内容,不存在该对象为 `null`) setResourceLoader(resourceLoader); } }

属性不多,构造函数都会进入最下面这个构造方法,主要调用了两个方法,如下:

调用父类的 registerDefaultFilters() 方法,注册几个默认的过滤器,方法如下:

protected void registerDefaultFilters() { // 添加 @Component 注解的过滤器(具有层次性),@Component 的派生注解都符合条件 this.includeFilters.add(new AnnotationTypeFilter(Component.class)); ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader(); try { this.includeFilters.add(new AnnotationTypeFilter( ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false)); logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning"); } catch (ClassNotFoundException ex) { // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip. } try { this.includeFilters.add(new AnnotationTypeFilter( ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false)); logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning"); } catch (ClassNotFoundException ex) { // JSR-330 API not available - simply skip. } }

添加 @Component 注解的过滤器(具有层次性),@Component 的派生注解都符合条件

也会添加 Java EE 6 的 javax.annotation.ManagedBean 注解过滤器,JSR-330 的 javax.inject.Named 注解过滤器

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

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