序
一直想认真读一本Spring源码级别解读的书,因为现在的Java程序员某程度上也是Spring程序员。
Spring已经占据了Java的生态,除了日常的Web后端开发要用到Spring。面试时候Spring也是Java程序员的一个必考察的一个点。随着现在面试官的套路越来越深,面试难度也越来越大。单纯地掌握Spring的使用是远远不够的。
现在习惯看书之前都先去豆瓣看看相关的书评,筛选一下要读的书籍。Spring源码相关的书籍,主流有三本。
技术内幕这本书我当时买了第一版,评价跟网友的一致,书中太多大量的Spring源码的粘贴,极其影响阅读。内容更像是源码的解析,而且由于Spring的源码有多层的嵌套与调用,看完作者的解读也很难看懂。
源码深度解析这书,我也粗略看过。同样也是按Spring源码的流程解读,内容苦涩。
Spring揭秘的评分很高,在豆瓣技术书来说。9分是一个很高的评分。
选书完毕,接下来就是要开始研读了。
概要
全书分七个部分,分别为
- 掀起Spring的盖头来
- Spring的IoC容器
- Spring AOP框架
- 使用Spring访问数据
- 事务管理
- Spring的Web MVC框架
- Spring框架对J2EE的服务集成和支持
分析一下作者的outline,前面三部分,起源,IoC,AOP 这个在意料之中。一般讲一个框架,数据库到新的技术,都会回顾一下此项技术的背景。而IoC是Spring的核心理念,AOP则是Spring的强大的功能。
其余的访问数据,事务,MVC框架,集成更偏向于使用的感觉,后续在读到的时候会再讨论。
掀起Spring的盖头来
Spring的发起人是Rod Johnson,框架的主要理念来源于他的 Expert One-On-One J2EE Development and Design。其实Spring对标的项目是EJB,当时EJB是一个比较盛行的J2EE的解决方案。但Rod Johnson觉得EJB不应该是J2EE的唯一选择,应该说Rob Johnson为了反对EJB而推出了Spring。可能当时他自己也没有想到Spring会变成Java的事实行也标准,现在的Java程序员几乎都是使用Spring进行开发。
这里提到的一个概念:POJO(Plain Old Java Object,简单Java对象),其实我们平常开发中用的VO,DTO,DO都是POJO,我的理解就是没有业务逻辑的简单Java对象,一般只有属性和对应的get set 方法构成。POJO这个概念最主要是用来跟EJB的企业Java Bean对对比,正正因为EJB中的Bean太重,太复杂,所以才衍生出POJO的概念。然后再触发Rob 的Spring构想。
《揭秘》中其余说的Spring的子项目,包括Spring Web Flow,Spring Web Services,Spring Security等众多子项目在这里就不在复述了。
第一部分只有一章,主要是引子的作用。说一说Spring的历史,也提到了Spring的由来的原因。其中对POJO的论述也是点到即止,对比《Beginning Spring》中用用POJO作为全书第一章没有说得很细。只是让读者对Spring有一个概念。
Spring的IoC容器
Spring的最核心的一个理念,就是容器。而IoC,DI也是我们在讨论Spring的时候听到最多的名词。
IoC的基本概念
这章先阐述两个定义:
- IoC:Inversion of Control,控制反转。
- DI: Dependency Injection,依赖注入。
这里作者也做了一个不错的补充,控制反转和依赖注入如果不是很严谨的区分可以说是看作类似的概念。利用依赖注入实现控制反转,我觉得这样的描述应该更准确。
Don't call us, we will call you.
这句好莱坞原则感觉是说到IoC的时候必定被引用一样。
这里作者用了“另一半”去比喻IoC,举的例子是:使用IoC之前,出门的时候要自己找衣服穿。使用了IoC之后,只需“一句话,一个眼神”就已让IoC帮你穿上衣服。
例子虽然比较形象生动,但有模糊了原本概念之嫌。
因为这里没有将IoC和DI的关键点,依赖关系明确说清楚。
书中原句:
通常情况下,被注入对象会直接依赖于被依赖对象
还是未能说清“依赖于对象”这件事,由此也未能很好引出“应尽量不依赖于实现,应依赖接口”的面向接口编程的原则。
细看之下,作者还针对此用了一个注释来说明。注释在图2-2下。
的确也像其他评论的同学说的,是良心之作。
此章(第2章)余下的几种注入方法:
- 构造方法注入
- setter方法注入
- 接口注入
还有这几种方式的比较,就是老生常谈了。
掌握大局的IoC Service Provider
第3章,作者先引入了标题的新概念。IoC Service Provider 即IoC服务提供者。用这个概念引出Spring中的IoC容器,BeanFactory,ApplicationContext也不失为作者的一点苦心。
个人觉得这章有两个作用
- 由IoC概念延展到IoC Service Provider的概念,随后延展到BeanFactory,ApplicationContext时候会更顺滑。
- 从侧面去引导读者去思考,一个IoC容器要做什么?我觉得这点是更加重要的,因为读源码的一个重点并不是解释,解读。而是跟源码的作者一样,去思考为什么要这样做。
IoC Service Provider 的职责
- 业务对象的构建管理(也就是怎样构建对象,我们一般的方法是使用 new 关键字)
- 业务对象的依赖绑定(对象之间,必然是存在依赖关系的,只有零件不组装起来,玩不转)
接下来作者给出了IoC管理对象依赖关系的秘密
- 直接编码方式
- 配置文件方式
- 元数据方式
这里不作赘述。
Spring的IoC容器之BeanFactory
这章作者在开头就给了一张图,正好衔接了上一章的IoC Service Provider的内容。
从图去引出,Spring的IoC容器其实也是基于IoC Service Provider的理念上扩展。
Spring 提供的容器:
- BeanFactory
- ApplicationContext
BeanFactory
与ApplicationContext
的区别,已经是很多书的“老生常谈”。包括:
BeanFactory
默认懒加载,ApplicationContext
扩展了BeanFactory
,官方推荐的容器是ApplicationContext
,还有ApplicationContext
的资源获取能力,消息发送能力,支持国际化等。
在作者给出的继承关系图也可以体现到。
本章就要说到全书,甚至是Spring的重点 BeanFactory
的原理。我自己看的时候也有会一个感觉,怕自己看不懂。因为BeanFactory
涉及到的类,接口,还有对象的构造,依赖绑定,关联过程都是非常繁琐的。如果只是按着代码把代码说一遍,其实读者是很难理解的。
我也在思考,如果有问你BeanFactory
的核心的原理,那么你怎么回答呢?怎样回答才可以准确又让对方明白呢?
作者的切入点:
有了BeanFactory
有什么不同?
答:没有不同,还是“拉拉扯扯”。这里的“拉”是指拉依赖的业务对象,而另一种方式是让BeanFactory推给你。
作者的思路:
有了BeanFactory
以后会怎样? --》 BeanFactory
怎样工作?(其中一种是XML方式) --》 XML运作方式 --》 容器的原理
看到这里,会开始感受到作者的风格。作者力求通过通俗,容易懂的方式去讲述Spring。
BeanFactory
如何管理依赖绑定的信息?
- 直接编码方式
- 外部配置文件方式
- 注解方式
依赖绑定的方式,跟之前的说的注入方式类似。这里不花费笔墨。
随后,在这章作者会说到Spring中 BeanFactory
的一个重要的实现DefaultListableBeanFactory
查看DefautListableBeanFactory
的类图,DefautListableBeanFactory
作为BeanFactory的一个重要实现之余,还实现了BeanDefinitionRegistry
接口。一方面,Spring的类命名的时候还是尽量符合语义还有能体现作用的,包括类图中的多个BeanFactory
。
BeanDefinitionRegistry
= Bean - Definition - Registry (Bean定义注册处)。
作者在书中将BeanFactory
比喻为图书馆,BeanDefinitionRegistry
比喻为书架,书最终是放在书架上。
我觉得这个比喻还是有不合理的地方,Bean定义注册处的一个重要作用。应该是体现在注册二字。
BenDefinition
实例负责保存对象的必要信息,这里的必要信息应该是指:足够可以构建对象实例的信息。包括class类型,是否抽象类、构造方法参数还以其他属性。
书架只是摆放书,这个比喻既没有体现注册,也没有体现到通过信息构造实例的过程。
到这里,作者给出了BeanFactory
的一部分的实现原理。
DefaultListableBeanFactory
会抽象为BeanDefinitionRegistry
,注册需要受管的Bean。
然后需要使用的时候,DefaultListableBeanFactory
会抽象为Bean的工厂,从工厂中获取需要的对象。
在讲解了配置文件方式,元数据方式后,来到了重点内容。
BeanFactory的XML之旅
这个章节是对 Xml的元素作一个系统的总结。
- beans 和 bean
- bean的属性
- 继承
- scope
说到scope,当然要说到singleton,prototype等。
singleton
标记为singleton的对象定义,在IoC容器中只存在一个实例,所有对该对象的引用将共享这个对象实例。
这里的单例是容器来只存在一个实例,与设计模式中的一个ClasLoader只有一个实例还是有区别的。
- 对象实例数量。一个容器中只存在一个共享实例。
- 对象存活时间。只要容器不销毁或退出,一直存活。
prototype
容器在接到该类型对象的请求的时候,会每次都重新生成一个新的对象实例给请求方。
request、session、global session
spring 2.0后新增加的,只适用于Web应用程序。
FactoryBean
其实我一直不理解,为什么写Spring相关的作者都喜欢写上这一句。
请不要混淆BeanFactory 和 FactoryBean。
我觉得要混淆还是很困难的。
本章最后,作者讲解了关于 scope的一个坑。
其实,简单来说。就是 prototype 的scope,也是需要经过容器去获取才会 new 一个新的实例给你。
容器背后的秘密
在面试中,关于Spring的最经常的一个问题。或者就是Spring容器的启动过程了。作者用三个小节来说明这个重点。
战略性观望
从标题就想到,是从整个大的流程来看的。
作者给出下图来描述大体的流程
容器的启动阶段,加载Configuration MetaData(元信息),然后再对元信息进行解析和分析,组成相应的BeanDefinition,然后将BeanDefinition注册到相应的BeanDefinitionRegistry
实例化阶段
先检查对象是否已经初始化。如果没有,则根据注册的BeanDefinition所提供的信息实例化被请求的对象,注入依赖。装配完毕之后,返回给请求方。
插手“容器的启动”
这个章节,最大的问题就是代码太多。作者把BeanFactoryPostProcessor
(连同完整的包名)在代码里面反复引述,严重影响阅读体验。
然后劈头盖脸就说 BeanFactoryPostProcessor
让人感觉很突兀。
Allows for custom modification of an application context's bean definitions,
adapting the bean property values of the context's underlying bean factory.
允许客户修改上下文的 Bean Definitions,适配上下文更根本的Bean工厂的Bean的属性值。
Spring中的类的命名都是有一定规律的,BeanFactoryPostProcessor
可以拆开为 BeanFactory Post Processor 也就是Bean工厂后置处理器。
从Spring的源码来看,BeanFactoryPostProcessor
的调用是在著名的
AbstractApplicationContext
中的refresh方法。
我觉得作者可以结合容器的refresh方法再说明BeanFactoryPostProcessor
可能会更好理解。
了解 Bean的一生
Bean的一生的重点,应该是在生命周期。作者也把Bean的生命周期罗列出来。然后重点说了
- Bean的实例化
- BeanPostProcessor
- 初始化Bean 与初始化方法
- 销毁Bean 与销毁方法
前四章算是一个引入,也讲到了 容器,Bean相关的概念。但如果是由我来说Spring是怎样完成容器的初始化,Bean的生命周期的管理,是否把这些知识点说出来就可以了呢?听我说的人可以理解,明白这个过程吗?
第一部分的笔记就先到这里,待续...