手写一个简单的Spring(二)

一、前文回顾

在上一篇文章中我们手写了一个简单的IOC容器,实现了根据传入的配置类扫描所有的“Bean”并转化成“BeanDefinition”;也实现了简单的getBean方法。简单的来说就是扫描+生成Bean,今天我们对比着Spring,看看Spring是如何实现这一功能的。

二、准备工作

1、Main

手写一个简单的Spring(二)_第1张图片

2、TestScan

手写一个简单的Spring(二)_第2张图片

三、源码分析

1、首先我们使用的是AnnotationConfigApplicationContext这个类,我们进入这个类,首先看它的构造函数。
手写一个简单的Spring(二)_第3张图片
可以看到,在构造函数中创建了一个ClassPathBeanDefinitionScanner的类,从名字中我们就大致可以推测出,这个类的作用是扫描ClassPath下的BeanDefinition,这个和我们自己写的有点类似。我们继续进入这个类中。
2、在当前类中可以找到一个名为“scan”的方法,这个方法的入参是包路径的数组,也就是说扫描的地址,然后返回本次扫描并注册成功的BeanDefinition数量。我们继续进入doScan方法
手写一个简单的Spring(二)_第4张图片
3、扫描Bean
手写一个简单的Spring(二)_第5张图片 不难看出,相较于我们写的Demo版本,Spring所提供的包扫描要复杂的多,不仅考虑到了Bean的作用域,还要给Bean设置名称、Bean的类型等等一系列的设置。上述代码中比较核心的是findCandidateComponents方法,该方法扫描出了所有原始的BeanDefinition。
手写一个简单的Spring(二)_第6张图片
从Debug中我们得知进入了else中的代码,也就是scanCandidateComponents方法。废话不多说直接Debug
手写一个简单的Spring(二)_第7张图片
从Debug的结果来看,Spring会拼接我们传入的路径,用于构建Resource(资源,这里的资源可以是文件、可以是网络IO等等)对象。
手写一个简单的Spring(二)_第8张图片
同时我们可以看到生成的Resource就是我们自己定义的两个类一个是Main,一个是TestScan。显然这两个类不用都被Spring注册成BeanDefinition,因为只有TestScan上有@Component注解,接下来我们看下Main是如何被过滤掉的。
手写一个简单的Spring(二)_第9张图片
Spring通过isCandidateComponent 来过滤不符合条件的类。(至于如何过滤的这里暂时放下不表,之后的文章中会有分析)至此,我们大致的了解了Spring是如何扫描Bean并且注册BeanDefinition的,希望对你有所帮助。

你可能感兴趣的:(spring,java)