互联网轻量级SSM框架解密:Spring、Spring MVC、MyBatis源码深度剖析(txt+pdf+epub+mobi电子书下载)


发布时间:2021-03-12 00:39:40

点击下载

作者:李艳鹏 等

出版社:电子工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

互联网轻量级SSM框架解密:Spring、Spring MVC、MyBatis源码深度剖析

互联网轻量级SSM框架解密:Spring、Spring MVC、MyBatis源码深度剖析试读:

前言

SSM是Spring、Spring MVC和MyBatis框架的组合,是目前Java领域使用非常广泛也非常稳定的开源Web框架,具有易搭建、开箱即用、配置丰富、扩展度高、运行稳定、开源社区活跃等优点。

本书以SSM的核心代码剖析为基础,突破Java Web研发瓶颈的束缚,选取Spring、Spring MVC 和 MyBatis 框架中易于理解的版本,深入剖析了其中各个模块的实现,从代码中挖掘常用的设计模式,为读者理解 Spring系列框架的可扩展设计艺术提供了方法论和优秀实践。

软件是一个密切关注实践的领域,源码是我们提升实践能力的优质学习资源,我们学习了各种设计模式,最终需要在源码中进行落地。当然,我们也需要从优秀的源码中挖掘设计模式及设计模式的应用场景,学习其中的设计艺术。

本书Spring源码剖析篇基于Spring 4.3.2版本,剖析了Spring上下文、Spring AOP和Spring事务的实现,并通过实例展示了框架陷阱的隐蔽性及学习框架原理的必要性。

Spring MVC源码剖析篇基于Spring MVC 3.0版本,这个版本相对简单、核心清晰,便于读者理解透彻,并主要讲解其中的设计模式及可插拔的设计思路。

MyBatis源码剖析篇基于MyBatis 3.4版本。轻量化、易集成和SQL资源易管理等特性为MyBatis带来了大量的用户,本篇致力于使读者对SQL语言、JDBC及数据访问方式有更深入的了解,也能看到工厂、Builder、代理、装饰者等设计模式在MyBatis中的大量应用。

我们在实际项目中会用到很多中间件,在搭建大型项目工程的时候,多数开发人员主要关注业务逻辑的实现,甚至不关心核心的非功能需求的质量,许多框架高级特性也经常被忽略,导致项目质量不过关。本书通过源码剖析的方式,带领读者挖掘优秀框架的经典设计,窥探框架中高级特性的实现方式,让开源爱好者和应用开发者快速了解 SSM 框架的内部设计细节、设计思路、编程技巧及高级功能特性等内容,为在实际项目中更加熟练地使用框架并巧妙地避开框架内的陷阱提供帮助。

本书对于互联网从业者,或者传统行业的IT工程师、架构师、技术经理、技术总监,以及想深耕IT行业的技术人员都有很强的借鉴性和实用价值。第1篇 深入剖析Spring源码第1章 Spring基础介绍

Spring是一款用于简化企业级Java应用开发的分层开源框架,它有着强大的扩展、融合能力,善于将各种单层框架完美地糅合在一起,并建立一个完整体系,统一、高效地构造可提供企业级服务的应用系统。

Spring的优势主要体现为以下几点。

◎ 降低了J2EE的使用难度,并且方便集成各种框架。

◎ 推荐及大量使用面向对象的设计思想,是学习Java源码的经典框架。

◎ 面向接口编程,而不是面向类编程,不断地利用Java的多态特性及良好的面向对象设计思想,来降低程序的复杂度及耦合度。

◎ 提供了测试框架,并且支持集成其他测试框架,使测试更容易,对测试程序的编写也更简单、高效。

本章讲解 Spring的核心结构,介绍其中的各个模块及其职责,并讲解设计及使用 Spring时的领域模型。1.1 Spring的核心结构

Spring是一个分层非常清晰并且依赖关系、职责定位非常明确的轻量级架构,主要分为8大模块:数据处理模块(Data Access/Integration)、Web模块、AOP(Aspect Oriented Programming)模块、Aspects模块、Instrumentation模块、Messaging模块、Core Container模块和Test模块,如图1-1所示,Spring依靠这些基本模块,实现了一个令人愉悦的融合了现有解决方案的零侵入的轻量级框架。图1-1

下面对这8大模块进行讲解。

1.数据处理模块(Data Access)

该模块由JDBC、Transactions、ORM、OXM和JMS等模块组成。

◎ JDBC模块提供了不需要编写冗长的JDBC代码和解析数据库厂商特有的错误代码的JDBC-抽象层。

◎ Transactions模块支持编程和声明式事务管理。

◎ ORM模块提供了流行的Object-Relational Mapping(对象-关系映射)API集成层,包含JPA、JDO和Hibernate等ORM框架。Spring对ORM的支持和封装主要体现在三方面:一致的异常处理体系结构,对第三方ORM框架抛出的专有异常进行了包装;一致的DAO抽象的支持,为每个框架都提供了模板类来简化和封装常用操作,例如 JdbcSupport、HibernateTemplate等;Spring的事务管理机制,为所有数据访问都提供了一致的事务管理。

◎ OXM模块提供抽象层,用于支持Object/XML mapping(对象/XML映射)的实现,例如JAXB、Castor、XMLBeans、JiBX和XStream等。

◎ JMS模块(Java Messaging Service)包含生产和消费信息的功能。

2.Web模块

该模块由Web、WebSocket、Servlet和Portlet等模块组成。

◎ Web模块提供了面向Web开发的集成功能。

◎ WebSocket模块提供了面向WebSocket开发的集成功能。

◎ Servlet 模块(也被称为SpringMVC 模块)包含 Spring 的 Model-View-Controller(模型-视图-控制器,简称MVC)和REST Web Services实现的Web应用程序。Spring MVC框架使Domain Model(领域模型)代码和Web Form(网页)代码实现了完全分离,并且集成了Spring Framework的所有功能。

◎ Portlet模块(也被称为Portlet MVC 模块)是基于Web和Servlet模块的MVC实现。Portlet和Servlet的最大区别是对请求的处理分为Action阶段和Render阶段。在处理一次 HTTP请求时,在 Action阶段处理业务逻辑响应并且当前逻辑处理只被执行一次;而在Render阶段随着业务的定制,当前处理逻辑会被执行多次,这样就保证了业务系统在处理同一个业务逻辑时能够进行定制性响应页面模版渲染。

3.AOP模块

该模块是Spring的代理模块,也是Spring的核心模块,它巧妙地利用了JVM动态代理和CGLIB动态代理面向过程编程,来实现业务零侵入、低耦合的效果。为了确保Spring与其他AOP框架的互用性,Sping AOP模块支持基于AOP联盟定义的API,也就是Aspect模块,与Spring IoC模块相辅相成。其中,我们熟知且常用的事务管理就是利用Spring AOP模块实现的。Spring AOP模块及Spring良好的架构设计及扩展性,使Spring可以融合基本上所有的模块及其他框架,成为真正的集大成者。

4.Aspects模块

该模块提供了与 AspectJ(一个功能强大并且成熟的面向切面编程的框架)的集成,它扩展了Java语言,定义了 AOP语法(俗称织入点语法),持有一个专门的编译器来生成遵守Java字节编码规范的Class文件,使用字节码生成技术来实现代理。

Spring自带AOP模块,并且集成了AspectJ框架,使原AspectJ使用者可以快速掌握Spring框架,这同样体现了Spring高融合的特性。

5.Instrumentation模块

该模块是 Spring 对其他容器的集成及对类加载器的扩展实现,其子模块 spring-instr ument-tomcat实现了Tomcat Instrumentation代理功能。

6.Messaging模块

该模块是从Spring集成项目(例如 Message、MessageChannel、MessageHandler及其他基于消息应用的基础模块)中抽象出来的,类似于基于注解的Spring MVC编程模块,包含一系列消息与方法的映射注解。

7.Core Container模块

该模块(也叫Spring核心容器模块)是Spring的根基,由Beans、Core、Context、SpEL四个子模块组成,这四个子模块如下所述。

◎ Beans模块和Core模块提供框架的基础部分,包含IoC(Inversion of Control,控制反转)和 DI(Dependency Injection,依赖注入)功能,使用 BeanFactory 基本概念来实现容器对Bean的管理,是所有Spring应用的核心。Spring本身的运行都是由这种Bean的核心模型进行加载和执行的,是Spring其他模块的核心支撑,是运行的根本保证。

◎ Context(包含 Spring-Context和 Spring-Context-Support两个子模块)模块建立在Core模块和 Beans模块的坚实基础之上,并且集成了 Beans模块的特征,增加了对国际化的支持,也支持Java EE特征。ApplicationContext接口是Context模块的焦点。Spring-Context-Support模块支持集成第三方常用库到Spring应用上下文中,例如缓存(EhCache、Guava)、调度Scheduling框架(CommonJ、Quartz)及模板引擎(FreeMarker、Velocity)。

◎ SpEL模块(Spring-Expression Language)提供了强大的表达式语言来查询和操作运行时的对象。

8.Test模块

该模块支持通过组合JUnit或TestNG来进行单元测试和集成测试,并且提供了Mock Object(模仿对象)方式进行测试。在该模块中定义了注释,例如@ContextConfiguration、@WebAppConfiguration、@ContextHierarchy、@ActiveProfiles,可以被用作元注释来创建自定义注解并避免整个测试套件的重复构造。1.2 Spring的领域模型

Spring的领域模型有三种,如下所述。(1)容器领域模型(Context模型):也叫作上下文模型,是 Spring的掌控域,对 Spring核心领域模型进行生命周期管理。也可以将其称为Spring的服务域,因为它为整个应用服务。(2)核心领域模型(Bean模型):体现了 Spring的一个核心理念,即“一切皆 Bean,Bean即一切”。Bean是应用运行时可执行的最小函数式单元,可以是一个属性单元,也可以是 Java 中的一个函数对象,更倾向于一种对象式的为某种特殊行为而生的可复用的概念,不受职责或者大小的限制。例如 Spring 上下文是一个 Bean,一个简单的描述型的对象也是一个Bean。Bean模型是Spring的核心服务实体域,是应用要操作的本身,是每个线程的真正执行者,也是整个会话生命周期的管理者,还是Spring对外暴露的核心实体。(3)代理领域模型(Advisor模型):Spring代理的执行依赖于Bean模型,但是Spring代理的生成、执行及选择都依赖于 Spring自身定义的 Advisor模型,只有符合 Advisor模型的定义,才能生成Spring代理。第2章 Spring上下文和容器

本章通过Spring容器的设计及加载机制来探秘Spring,彻底揭开其神秘的面纱。

Core Container模块是Spring整个架构的根基,其核心概念是BeanFactory,也正是这个概念让Spring成为一个容器,帮助Spring管理Bean,并提供DI(依赖注入)功能来实现对Bean的依赖管理,使用配置方式来达到与业务代码及框架代码的分离。

Context模块即Spring上下文模块(也叫Spring Context模块),是Core Container模块的子模块,它让 Spring 真正成为一个可执行框架。这个模块扩展实现了 BeanFactory,让它不仅仅是 BeanFactory。笔者认为,Context 模块虽然是 BeanFactory 的实现者,但更是一个框架,这才是它的主要职责。这个模块为Spring的扩展和架构继承提供了非常多的可能,比如校验框架、调度框架、缓存框架、模板渲染框架,等等。2.1 Spring上下文的设计

Spring Context模块是Spring Core Container模块中的Spring Context子模块,这个模块让Spring成为一个执行框架,而不仅仅是对BeanFactory概念的扩展。也正是Spring上下文的设计,让Spring可以提供很多企业级服务的定制。下面从Spring Context的核心类图设计入手,来详细讲解Spring上下文。

如图2-1所示,Spring容器的设计和实现是对抽象模板设计模式的灵活驾驭,其中大量使用了 Java 语言中的继承关键字来实现代码的高复用,若不能很好地掌握继承的用法,则非常有风险,比如子类重写了父类的方法实现,但是子类的子类仍然依赖这个基类(父类的父类)的原始实现,此时一旦重写程序,将要发生的变化则不可预估(因为它的子类可能还在依赖它的父类的实现逻辑,此时它的子类无法感知它的父类重写,所以无法预测子类的执行结果是什么样的),而且在继承层级较多时更有风险。而 Spring大神们用合理的分层职责划分及强大的抽象设计能力完美利用了继承的优点并且规避了风险,是我们使用继承设计的教科书式框架设计。图2-1

下面说说核心抽象类的职责。(1)ApplicationContext 是整个容器的基本功能定义类,继承了 BeanFactory,这说明容器也是工厂的多态实现。其实它利用了代理的设计方法,内部持有一个 BeanFactory 实例,这个实例替它执行 BeanFactory 接口定义的功能,这种典型的代理模式应用也是非常巧妙的。(2)AbstractApplicationContext是整个容器的核心处理类,是真正的Spring容器的执行者,在内部使用了模板方法,实现了高复用、高扩展,实现了Spring的启动、停止、刷新、事件推送、BeanFactory方法的默认实现及虚拟机回调的注册等。在本书中讲解Spring容器的加载方式时,会以这个类作为主线来讲解。(3)GenericApplicationContext是Spring Context模块中最容易构建Spring环境的实体类,涵盖了Spring Context的核心功能,在不需要特殊定制的场景下可以实现开箱即用。如图2-1所示,AnnotationConfigApplicationContext完美利用了GenericApplicationContext的封装性和对外简便性,如果想扩展适合自己业务的轻量级 Spring 容器,使用GenericApplicationContext这个基类则会非常容易上手。AnnotationConfigApplicationContext的构造方法先传入一个 class 数组,再创建一个可执行的上下文实例来构造一个可运行的Spring运行环境,使用起来非常简便。(4)AbstractRefreshableApplicationContext是 XmlWebApplicationContext的核心父类,如果当前上下文持有BeanFactory,则关闭当前BeanFactory,然后为上下文生命周期的下一个阶段初始化一个新的BeanFactory,并且在创建新容器时仍然保持对其父容器的引用。(5)EmbeddedWebApplicationContext是在Spring Boot中新增的上下文实现类,是使用自嵌容器启动Web应用的核心上下文基类。

Spring Boot在启动时,启动Spring环境并使用内嵌Tomcat容器加载运行Web环境,源码如下。

Spring Boot的相关细节在本书中不再赘述,总之,Spring Boot依赖于Spring容器,也是基于 Spring 框架产生的,其中体现了 Spring 良好的设计和扩展兼容性,了解 Spring核心机制对了解Spring Boot的设计理念和实现有非常大的帮助。2.2 Spring容器BeanFactory的设计

Spring 的核心功能就是实现对 Bean 的管理,比如 Bean 的注册、注入、依赖等。而Spring容器提供了依赖注入这个特征,以实现 Spring 容器对 Bean的管理,而且使用 IoC实现了对Bean的配置与实际应用代码的隔离。其中,Core Container模块的核心概念就是BeanFactory,它是所有Spring应用的核心。因为Spring的核心模型就是Bean模型,所以需要在管理Spring Bean的基础上保证Spring应用的运行。

下面先通过BeanFactory的类图设计入手,展示Spring各个BeanFactory之间的关系,进而讲解BeanFactory的主要职责及作用,如图2-2所示。图2-2

BeanFactory接口是Bean容器设计中基本的职责定义接口,定义了按照名称、参数、类型等几个维度获取、判断Bean实例的职能。

HierarchicalBeanFactory只是对BeanFactory进行了扩展,定义了父容器(Parent Bean Factory)及判断当前Bean的名称是否在当前Bean工厂中等。

ConfigurableBeanFactory 提供了设置父容器接口、指定类加载器的职能,并且为当前容器工厂设计Bean的定制型的解析处理器、类型处理器等,主要目的是实现对BeanFactory的可配置性。

AutowireCapableBeanFactory提供了 Bean的创建、注入职能,并且提供了对 Bean初始化前后的扩展性处理职能,主要职责是处理在当前工厂中注册的 Bean 实例并使其达到可用状态。

ListableBeanFactory实现了对Bean实例的枚举,以及对有某些共同特征的 Bean的管理,并且按照Bean名称、Bean实例、Bean类型获取Bean实例。

ConfigurableListableBeanFactory 除了集成了 ListBeanFactory、AutowireCapableBean Factory、ConfigurableBeanFactory 这些接口的所有职能,还扩展了修改 Bean 定义信息和分析Bean的功能,并且实现了预实例化单例Bean及冻结当前工厂配置等功能。

AbstractBeanFactory实现了对基本容器功能定义的模板式封装和实现,同时实现了对Bean 信息的注册,但是对 Bean 的创建及 Bean 定义描述信息相关的处理使用了抽象化处理的方式并交由继承者实现。

AbstractAutowireCapableBeanFactory 主要解决 Bean 之间的依赖和注入问题,其中实现了 Bean的创建方法。因为Bean并不是孤立存在的,很有可能存在 Bean的相互依赖关系,所以只有在解决 Bean 的依赖的前提下,才能实现 Bean 实例的创建。这也就是AbstractBeanFactory不能直接创建Bean方法的原因。

DefaultListableBeanFactory 提供了对 Bean 容器的完全成熟的默认实现,可以直接对外使用。

在 Spring Context 模块中,许多依赖 BeanFactory 的场景都通过 DefaultListableBean Factory类来实现对Bean的管理、注入、依赖解决、创建、销毁等功能。

XmlBeanFactory 继承 DefaultListableBeanFactory 并且内部持有 XmlBeanDefinition Reader 属性(该属性用来实现对 XML 文件定义的 Bean 描述信息的加载、解析和处理)的Bean工厂容器。2.3 Spring父子上下文与容器

这里通过Context框架来讲解Spring父子上下文、父子容器的使用场景和实现细节。

从 ApplicationContext 中可以看出(见图 2-3),Spring 提供了为当前 BeanFactory 和Application Context设置父子引用的功能方法,BeanFactory像一个单向链表节点一样支持Spring的多容器场景。图2-3

ApplicationContext接口对外提供获取父上下文的方法,既然能对外获取父上下文,那么肯定有上下文属性的设置方法或者初始化方法。最常用的是用构造方法和 set 方法手工指定,相关代码如下。

在Spring MVC环境中存在Spring父子容器时,子容器可以复用父容器的Bean实例,从而避免重复创建。

在使用Spring MVC时,如下配置会出现在 web.xml中。

由于在 web.xml 中标签的加载早于标签的加载,所以ContextLoaderListener在启动后会先创建一个 Spring容器,之后在 Dispatcher启动时还会实例化一个容器。

HttpServletBean是HttpServlet的子类,它重写了init方法,调用如下方法进行初始化:

创建Spring Web容器:

Spring 父子容器中的 Bean 是如何被使用的呢?Spring 父子容器从设计上来看,每个容器都可能持有一个父容器,这种设计为各个容器间的共享提供了设计基础,实现了在设计模式Flyweight中提到的对象共享和复用。相关代码如下:

可是我们设置的是父容器,而此处用的是父工厂,很多人在研读Spring源码时会不理解,并且容易混淆容器和工厂的概念,这时可通过在 Spring 类图中熟悉 Spring 容器和上下文的设计来理解。Spring ApplicationContext 有父子上下文的概念,Spring BeanFactory也有父子工厂的概念,但是 ApplicationContext的实现者也是BeanFactory的实现者,虽然在 ApplicationContext 接口中也声明了 BeanFactory 接口中的功能,但其实 Application Context 和 BeanFactory 并不是一个概念,只是由于在 AplicationContext 实例中持有了BeanFactory实例,也就是说BeanFactory实例只是AplicationContext的一个属性,由这个属性来帮助ApplicationContext对外提供BeanFactory定义的功能实现。

AbstractRefreshableApplicationContext 是 Spring Web 容器的核心基类,在 Spring AbstractApplicationContext启动时调用refreshBeanFactory方法,相关代码如下:

由于Spring MVC中的容器之间存在关联(也就是父子容器),所以容器之间可以互相访问,子容器也可以共用父容器中的 Bean。但是父容器不能共用子容器的 Bean,这是因为当父容器已经启动时,子容器还没有实例化并启动,这时如果父容器引用子容器的Bean,则是不可能正常运行的。

对于 Spring 子容器什么时候不能使用父容器的 Bean,即如何隔离容器之间的访问,在6.1节会进行详细讲解。第3章 Spring加载机制的设计与实现

前面讲解了Spring上下文的设计和实现,那么Spring上下文是怎么加载起来的?Sping是怎么实现灵活扩展的?Spring在加载时都做了什么?只有明白了这些,我们才能更好地明白Spring的实现细节,从而更好地驾驭Spring的二次开发及扩展。

很多知名的中间件都是依赖 Spring 上下文来实现的,很多企业应用也是依赖 Spring作为基础框架来搭建和实现的,所以了解Spring加载机制对于开发通用的中间件来说很重要。3.1 Spring ApplicationContext的加载及源码实现

若想了解Spring的加载机制,则必须先明白Spring ApplicationContext(后简称Spring上下文)到底是什么、是怎么设计的、有哪些职能,以及与Spring BeanFactory的关系。

如图3-1所示,ApplicationContext是 Spring上下文的核心接口,描述了 Spring容器的所有基本功能,是Spring Context(Spring上下文)模块的核心设计。

ApplicationContext是围绕着Spring整体来设计的,从类型上看它虽然是BeanFactory(因为它是 BeanFactory 的实现类),但比 BeanFactory 的功能更丰富,可以理解为ApplicationContext扩展了BeanFactory,是Spring ApplicationContext框架的核心设计。从图3-1可以看出,ApplicationContext是一个复杂的集成体,它集成了环境接口、BeanFactory接口、消息接口、上下文事件推送接口及配置源信息解析接口。图3-1

下面通过理解ApplicationContext最重要的核心实现类 AbstractApplicationContext,来深入理解Spring容器的核心实现。

如图2-1所示,AbstractApplicationContext是ApplicationContext实现类中的核心抽象模板类,其中的核心方法refresh就是由AbstractApplicationContext提供的。

refresh方法是通过典型的模板方法设计模式实现的,但是我们都知道模板方法有一个最大的弊端,就是要非常慎重地修改,特别是其顺序不能改变,因为一旦发生了改变,已经实现好的子类就不会按照当初设计的目标去执行了。

Spring的作者Rod Johnson是怎么规避模板方法的弊端的呢?一是对整个Spring模型的理解及对各个模块职责的明确划分;二是在使用抽象模板的高复用性的同时增加支持重写及注册响应核心处理实体的回调函数,来增加整个模板方法的扩展性。

Spring 上下文的加载虽然使用了模板模式,但是每个方法依赖的子类实现都非常复杂,我们以代码调用依赖的顺序(如图3-2所示)理解Spring上下文的加载,同时从时序图中看看各个子类是怎么利用AbstractApplicationContext模板方法来实现自己的实例加载的。了解这些核心子类的职责,对于以后自己扩展、二次开发Spring容器有很好的帮助。图3-2

1.XmlWebApplicationContext(Web项目使用的容器加载类)

如图3-2所示,XmlWebApplicationContext 只负责配置文件部分的加载;Application Context 负责整个容器的加载;AbstractRefreshApplicationContext 负责创建 Bean 工厂;AbstractRefreshConfigApplicationContext、AbstractRefreshWebApplicationContext负责处理配置的加载及Web环境的准备;XmlApplicationContext负责XML文件的加载、读取和解析。

对于Bean的后置处理器的执行源码,会在4.3节结合Bean的运行加载机制进行详细说明。我们先以 XmlApplicationContext 上下文的加载实现为主线来了解 Spring 上下文的加载机制。Spring的设计非常巧妙,并且对接口和代理的使用非常多,我们在读源码时可能抓不到重点,容易跟丢源码,这时抓住主线,在掌握整体思路后再看与主线相关的其他实现,可事半功倍。

从如上代码可以看出 XmlWebApplicationContext 是怎么巧妙利用 AbstractApplicaiton Context这个核心基类,并且灵活扩展适应Web场景的上下文实例的。

2.AnnotationConfigEmbeddedWebApplicationContext

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载