IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 可能是最卷的的Spring源码系列(三):AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner源码分析 -> 正文阅读

[Java知识库]可能是最卷的的Spring源码系列(三):AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner源码分析

上篇文章已经简单介绍了AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner的功能,这篇文章将详细的分析这两个对象
简述AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner
在分析这两个类之前再贴一下AnnotationConfigApplicationContext的继承关系
在这里插入图片描述
可以看到AnnotationConfigApplicationContext有实现一个AnnotationConfigRegistry接口,这个接口里面有两个方法,先说结论register是有AnnotatedBeanDefinitionReader完成的,scan是由ClassPathBeanDefinitionScanner完成的

在这里插入图片描述
再看源码
在这里插入图片描述
在这里插入图片描述
这里我们就知道了AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner分别完成了AnnotationConfigApplicationContext两个方法的实现,那它们还有没有其他的作用呢?

1、AnnotatedBeanDefinitionReader

这个类的初始化的时候就完成了一件事就是把几个固定的postProcessor包装成BeanDifinition(BeanDifinition后面会专门写一篇文章进行分析,现在知道这个概念就可以),然后放入到容器内(另外BeanFactory有个子类为DefaultListableBeanFactory,它有个成员变量beanDefinitionMap,这里会把所有的BeanDefinition放入beanDefinitionMap)。另外一个作用就是刚才说到的实现了AnnotationConfigApplicationContext的register方法
在这里插入图片描述

1.1 把几个固定的postProcessor包装成BeanDifinition,并放入容器

这是reader初始化的入口,依次点进去
在这里插入图片描述
构造方法
在这里插入图片描述

构造方法重载
在这里插入图片描述
这里我们看到他除了初始化了两个成员变量外还执行了一个

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

这是一个静态方法,我们点进去就能看到它完成了【把几个固定的postProcessor包装成BeanDifinition】这个流程
点进去
在这里插入图片描述
构造方法重载
在这里插入图片描述
最终包装BeanDifinition并注册到容器的流程就在这里

1.2 提供AnnotationConfigApplicationContext.register()方法的的实现

从下图可以看到AnnotatedBeanDefinitionReader为AnnotationConfigApplicationContext提供了register方法的实现
在这里插入图片描述
点进去为循环调用
在这里插入图片描述
点进去才是真正的实现

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
			@Nullable BeanDefinitionCustomizer[] customizers) {

		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
		// 根据元数据确定是否需要跳过 实例化BeanDefinition时会有默认的元数据生成
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}
		// 设置supplier  supplier不为空,就不再利用反射生成单例,而是由supplier提供
		abd.setInstanceSupplier(supplier);
		// 设置作用域
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		abd.setScope(scopeMetadata.getScopeName());
		// 由beanNameGenerator生成beanName
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
		// 给BeanDefinition设置默认值
		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
		// class有没有注解
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
				if (Primary.class == qualifier) {
					abd.setPrimary(true);
				}
				else if (Lazy.class == qualifier) {
					abd.setLazyInit(true);
				}
				else {
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}
		// 自定义工厂时的回调
		if (customizers != null) {
			for (BeanDefinitionCustomizer customizer : customizers) {
				customizer.customize(abd);
			}
		}

		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		// 真正的王BeanDifinition里面注册
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

可以看到最后一行有把BeanDifinition存到BeanDifinitionMap中

2、ClassPathBeanDefinitionScanner

ClassPathBeanDefinitionScanner主要完成了扫描,但是具体的扫描有两种实现,第一种是AnnotationConfigApplicationContext.scan方法中有调用ClassPathBeanDefinitionScanner的scan方法(这时使用默认的扫描规则,默认扫描规则是实例化的时候指定的)
在这里插入图片描述
方法重载

再次重载
在这里插入图片描述
指定默认的规则

第二种是为重新new一个ClassPathBeanDefinitionScanner(也就是不适用AnnotationConfigApplicationContext中的ClassPathBeanDefinitionScanner类型的成员变量),为其指定个性化扫描规则完成扫描,spring中的ConfigurationClassPostProcessor就这么干的,mybatis也是这么干的,这个会放在后面分析
下面是AnnotationConfigApplicationContext.scan的调用过程
在这里插入图片描述
方法重载
在这里插入图片描述
进入doScan方法
在这里插入图片描述
findCandidateComponents方法真正执行扫描
在这里插入图片描述
方法重载

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			// 把包名转换为路径
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
			// 从相关路径中扫描出所有的类,里面主要保存了相关class文件的InputStream
			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				// 判断InputStream指向的class是否存在
				if (resource.isReadable()) {
					try {
						// 通过asm进行扫描并把扫描结果包装为MetadataReader
						MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
						// 验证是否符合扫描规则
						if (isCandidateComponent(metadataReader)) {
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							sbd.setSource(resource);
							if (isCandidateComponent(sbd)) {
								if (debugEnabled) {
									logger.debug("Identified candidate component class: " + resource);
								}
								candidates.add(sbd);
							}
							else {
								if (debugEnabled) {
									logger.debug("Ignored because not a concrete top-level class: " + resource);
								}
							}
						}
						else {
							if (traceEnabled) {
								logger.trace("Ignored because not matching any filter: " + resource);
							}
						}
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to read candidate component class: " + resource, ex);
					}
				}
				else {
					if (traceEnabled) {
						logger.trace("Ignored because not readable: " + resource);
					}
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}

这里真正执行了扫描,这里使用的是asm的扫描方式,这里我们只了解把指定包里的类扫描到容器里面就可以,关于asm的扫描后面会专门有一篇文章进行讲解,欢迎关注本系列的课程。
这里的扫描只是AnnotationConfigApplicationContext.scan的执行过程,关于ConfigurationClassPostProcessor的扫描过程,请关注后续的文章。
如果想要第一时间获取本系列的更新,请关注公众号:
在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-25 11:31:22  更:2021-07-25 11:32:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 10:35:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码