前言
spring源码里面包含了很多的模块,也提供了很多功能,如果去一一叙述这些模块及其对应的功能,必然会是长篇大论,我个人比较讨厌一开始就去介绍所有的模块的功能,虽然能够让我了解整体的项目结构,但是读的时候却稍显枯燥,所以我决定跳过最基础也是最常见的模块的概览部分,直接进入源码的学习。
从哪儿开始入手学习spring的源码呢?
在我刚接触spring的时候,就不可避免的接触到了两个词汇---IOC和AOP,几乎每一本教材,每一篇blog都会反复的提到这两个词,阐述其意义,其重要性。
讲道理的话,在刚开始学习spring的时候,我不是很明白这两个词汇的意义,感觉很抽象,理解起来很片面,总感觉抓不到核心的地方,后来随着对spring使用的增多,才慢慢的理解了IOC和AOP的意义。 现在想想,在那时候,IOC和AOP真是我学习spring的一道坎。
所以我觉得学习spring还是从这两个词汇入手吧,毕竟从哪摔倒从哪爬起来不是。
先学会IOC和AOP相关的知识,这样由理解核心实现入手,然后再抽丝剥茧的学会他们外层的技术,应该会容易很多吧?
Spring官方文档
该文档记录了spring框架的核心技术实现,参考该文档,可以更快的理解spring核心技术。
Spring IOC概念的简单理解
对于spring框架来说IOC无疑是其最核心的技术之一,他改变了我们创建实例时的过程和思维,提供了一种全新的实例创建过程。 在不使用IOC的前提下,我们创建一个对象实例,通常都会手动的new出该对象实例,之后再根据需要去设值其依赖的对象,这是一种比较常见的方式,我们维护着整个对象实例的生命周期,我们自己负责对象实例的创建,同时我们也自己维护着对象之间的依赖关系等一系列操作。(PS:虽然对象的销毁掌握在GC手里,但是我们依然可以很明确的知道对象在何时就开始进入清理倒计时。)
而对于spring IOC来讲,他会维护一个容器,容器持有所有对象的引用以及对象之间的依赖关系 ,当我们需要使用一个对象的时候 ,直接从容器中拿出来该对象使用就可以了,容器会帮助我们完成对象的创建,对象实例之间依赖的创建。
这两者有一个很明显的区别就在于:常规方式下,我们几乎手动维护了整个对象实例的生命周期,在整个过程中我们需要自己手动组装我们需要的对象实例,而在使用spring IOC的前提下,我们仅仅只需要告诉容器对象之间的依赖关系,spring就会帮助我们完成包括组装对象在内的一系列操作。
前者,就好比我们自己买食材自己做饭,而后者更像我们去饭店点菜吃饭,一个亲力亲为,一个坐等享受~
为什么要从ClassPathXmlApplicationContext
类入手。
通过前面关于spring IOC概念的叙述中,我们不难理解,spring IOC技术的实现依赖与一个维护了所有对象及其依赖关系的容器,那么这个容器是什么呢?
spring源码中有一个最基础的类叫做BeanFactory
,该类提供了一个能够管理任意类型对象的高级配置机制,而该类也恰好就是我们入手学习spring源码的一条线索,但是我们在实际使用spring的过程中几乎很少会使用到BeanFactory
,反而其子实现ApplicationContext
使用的更多,这是因为BeanFactory
仅仅只定义了容器的基础功能,而ApplicationContext
在基于BeanFactory
定义的功能基础上实现了更多的功能,所以一方面ApplicationContext
是BeanFactory
的实现类,另一方面ApplicationContext
也是BeanFactory
的超集。
如果从ApplicationContext
入手学习,我们不得不又接触另一个叫做ClassPathXmlApplicationContext
的类,该类是在初学spring时候就会接触到的一个类,它实现了加载XML文件来初始化Spring容器的能力。
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext('{{Spring XML配置文件}}');
和其实现类似功能的类还有很多,比如:FileSystemXmlApplicationContext
,AnnotationConfigWebApplicationContext
。
但是因为相对来说,接触更多的是ClassPathXmlApplicationContext
,通常我们也会使用该类作为我们使用spring项目的入口。
就像我们调试代码要从main方法开始一样,调试spring也就从该类开始吧~
初识ClassPathXmlApplicatioContext
ClassPathXmlApplicationContextt
类位于spring-context
项目org.springframework.context.support
包下。
在整个源码调试过程中,默认使用IntelliJ IDEA工具。
我们在IDE工具内打开该类,
之后输入快捷键ctrl+alt+u打开该类的UML图,可以看到其中大概涉及了二三十个类或接口,其中就有我们刚才提到的BeanFactory
接口以及ApplicationContext接口
。
万事开头难,既然找到了入口,接下来的任务就是根据类图,从顶层开始大概了解涉及到的类和接口的作用。
BeanFactory
BeanFactory接口是整个spring容器的底层接口,他定义了在spring中作为一个bean容器需要提供的基本功能——管理Bean定义。
这里有一个好玩的问题,什么是Bean?Bean定义又是什么?
bean以及bean定义的概念
简单的理解bean其实就是java对象,是在spring容器中对java对象的一个称谓,就好像二狗在学校被称为学生一样,二狗还是那个二狗,只不过他多了一个学生的称号,那是不是其他人也能成为学生呢?当然可以,前提是这些人通过入学考试,对于Spring bean也是一样的,java对象还是那个java对象,只不过当他被spring管理之后它就多了bean的称号。
那么什么是Bean定义呢,这里还是要说一下二狗哥,二狗哥进了学校之后,招生办的人就给二狗哥搞了个学籍,学籍里面详细记录了二狗哥作为学生所需的所有数据,什么姓名啊,性别啊,品种(。。呸。。这个不算),年龄啊之类的。这个学籍以后就是二狗哥学生身份的依据了,以后学校就根据这个学籍来管理二狗哥。
一样的道理,当一个java对象被spring容器管理之后,spring会根据这个对象生成一个bean定义,这个bean定义里面了包含了描述bean对象的元数据,emmm...也就是说用来描述bean对象的元数据构成了bean定义。
BeanFactory的概念
在spring中,BeanFactory通常被认为是所有bean的注册中心,它集中进行bean定义的维护和管理操作,因此,BeanFactory也就不可避免的需要维护大量的bean定义,根据常识:
在现实生活中,当需要管理大量同类型实体的时候,我们都会为这些实体提供一个能够识别该实体的唯一标识,比如:中国公民的身份证号,汽车的车牌号等。
对于spring容器来说,道理是一样的道理,spring给所有受spring管理的bean都会生成一个容器内唯一的String类型的唯一标识,并将会根据该标识对bean定义进行维护和管理。
BeanFactory的源码解析
BeanFactory位于
spring-beans
模块下的org.springframework.beans.factory
包内,
BeanFactory中定义了13个方法,1一个常量,其大致作用如下图:
其中常量FACTORY_BEAN_PREFIX
涉及到了一个叫做FactoryBean
的概念,简单的来说FactoryBean就是spring对工厂模式的一种通用实现,通过实现FactoryBean
来实现工厂模式的Bean,会被spring容器特殊处理,这里先提出来,后续再继续深入。