Spring核心技术和案例实战

978-7-115-59411-2
作者: 郑天民
译者:
编辑: 武晓燕
分类: Spring

图书目录:

详情

本书主要介绍基于Spring框架构架企业级应用程序的技术体系和工程实践。全书从Spring概述、Spring Boot、Spring Cloud和响应式Spring等4个方面由浅入深地介绍了Spring。本书首先介绍了Spring框架的基础概念,然后介绍了Spring Boot的核心功能特性,接着介绍了用于构建主流微服务架构的Spring Cloud,最后讲解了响应式编程技术。本书通过3个完整的案例来系统展示具体的实现过程。 本书面向广大服务端开发人员,读者不需要有很高的技术水平,也不限于特定的开发语言,但熟悉Java EE常用技术并掌握一定的系统设计基本概念有助于更好地理解书中的内容。同时,本书也适合对Spring框架有兴趣的开发人员阅读,希望本书能为读者的日常学习和开发工作带来启发与帮助。

图书摘要

版权信息

书名:Spring原理与实战

ISBN:978-7-115-59411-2

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。


版  权

著    郑天民

责任编辑 武晓燕

人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

读者服务热线:(010)81055410

反盗版热线:(010)81055315

读者服务:

微信扫码关注【异步社区】微信公众号,回复“e59411”获取本书配套资源以及异步社区15天VIP会员卡,近千本电子书免费畅读。

内容提要

本书主要介绍基于Spring框架构架企业级应用程序的技术体系和工程实践。全书从Spring概述、Spring Boot、Spring Cloud和响应式Spring等4个方面由浅入深地介绍了Spring。本书首先介绍了Spring框架的基础概念,然后介绍了Spring Boot的核心功能特性,接着介绍了用于构建主流微服务架构的Spring Cloud,最后讲解了响应式编程技术。本书通过3个完整的案例来系统展示具体的实现过程。

本书面向广大服务端开发人员,读者不需要有很高的技术水平,也不限于特定的开发语言,但熟悉Java EE常用技术并掌握一定的系统设计基本概念有助于更好地理解书中的内容。同时,本书也适合对Spring框架有兴趣的开发人员阅读,希望本书能为读者的日常学习和开发工作带来启发与帮助。

作者介绍

郑天民,日本足利工业大学信息工程学硕士。拥有10余年软件行业从业经验,目前在一家大健康领域的创新型科技公司担任CTO,负责产品研发与技术团队管理工作。开发过10余个面向研发人员的技术和管理类培训课程项目,在架构设计和技术管理方面具有丰富的经验和深入的理解。他还是阿里云MVP、腾讯云TVP、TGO鲲鹏会会员。著有《Apache ShardingSphere实战》《Spring响应式微服务:Spring Boot 2 + Spring 5 + Spring Cloud实战》《系统架构设计》《向技术管理者转型》《微服务设计原理与架构》《微服务架构实战》等图书。

前  言

在当下的互联网应用中,业务体系日益复杂,同时业务功能的发展往往还伴随着不断的变化。以典型的电商类应用为例,其承载的业务功能复杂度以及快速迭代的开发要求,对比5年前的同类业务系统,面临着诸多新的挑战。这些挑战中的核心点就是“要快”。如何快速、高效地实现系统功能,又要保证代码持续可维护,成为一个非常现实且亟待解决的问题。

面对这样的挑战,需要强调一点,就是保持开发过程的简单性,而这种简单性很大程度上取决于开发框架。对于Java EE领域而言,Spring无疑是主流的开发框架。Spring是一个集成的开源框架,内部整合了很多第三方组件和框架。事实上,Spring自身的功能特性同样非常丰富,而且在使用上也存在一些最佳实践。

本书主要介绍基于Spring框架构建企业级应用程序的技术体系和工程实践。本书围绕日常开发过程中所涉及的各种开发需求,讨论了Spring框架所提供的各项解决方案,包括使用Spring Boot开发Web应用程序、使用Spring Cloud开发微服务系统,以及使用Spring 5和响应式编程技术开发响应式系统。同时,本书将基于这些技术体系构建3个完整的案例系统并给出具体的实现过程和示例代码。本书共有19章内容。

第1章,直面Spring。本章作为开篇总领全书,从Spring框架的基本概念出发,引出Spring家族生态和技术体系,以及框架所提供的整体定位和解决方案。本章围绕Spring所具备的各项功能,从Spring Boot与Web应用程序、Spring Cloud与微服务架构、Spring 5与响应式编程等维度切入,分别讨论针对不同应用场景的技术体系。

第2章,Spring Boot配置体系。本章将介绍Spring Boot中的自动配置解决方案,以及如何使用该配置体系来实现复杂的多维配置以及定制化配置。

第3章,Spring Boot数据访问。本章将介绍Spring Boot提供的针对关系数据库的一系列数据访问组件。同时,也将提供对Spring Data这个统一的数据访问抽象框架的全面介绍。

第4章,Spring Boot Web服务。本章将介绍基于Spring Boot构建一个Web服务的系统方法,以及如何实现多个Web服务之间的交互和集成。

第5章,Spring Boot消息通信。本章将介绍消息通信的基本概念,以及如何基于Spring Boot所提供的模板工具类完成与Kafka、ActiveMQ、RabbitMQ等多款主流消息中间件的集成。

第6章,Spring Boot系统监控。本章将介绍Spring Boot中即插即用的服务监控技术组件。Spring Boot内置的各种度量指标、监控端点和可视化管理功能是该框架的亮点。

第7章,SpringCSS:Spring Boot案例实战。本章将基于完整的案例给出Spring Boot各个技术组件的具体应用方式和过程,其中既涉及单个服务的构建方式,也涉及多个服务之间的交互和集成。本章将针对技术组件给出详细的示例代码,并提供能够直接应用于日常开发的实战技巧。

第8章,Spring Cloud注册中心。本章将介绍服务治理的解决方案,以及使用Eureka来构建注册中心服务器/客户端组件的方法和实现原理。同时,也将结合注册中心介绍使用Ribbon实现客户端负载均衡的方法。

第9章,Spring Cloud服务网关。本章将介绍服务网关的构建方式,并给出Spring Cloud Gateway这款典型的服务网关的使用方法和工作机制。

第10章,Spring Cloud服务容错。本章将介绍服务容错思想和模式,并介绍Spring Cloud Circuit Breaker与Hystrix、Resilience4J等熔断器的集成。

第11章,Spring Cloud配置中心。本章将介绍分布式环境下的配置中心解决方案,并介绍如何基于Spring Cloud Config实现配置中心服务器的构建,以及客户端组件的集成。

第12章,Spring Cloud消息通信。本章将介绍基于Spring Cloud Stream实现消息发布者和消费者的开发方法,并基于Spring Cloud Stream基本架构剖析其集成Rabbit、Kafka等主流消息中间件的实现过程。

第13章,Spring Cloud服务监控。本章将介绍Spring Cloud Sleuth的基本原理,以及基于Spring Cloud Sleuth与Zipkin实现可视化监控的整合过程,同时给出基于Tracer在访问链路中创建自定义跟踪信息的实现方法。

第14章,SpringHealth:Spring Cloud案例实战。本章将基于案例帮助读者全面梳理基于Spring Cloud的微服务系统开发技术组件。通过完整的案例系统,给出各个组件的具体应用方式和过程,并提供能够直接应用于日常开发的实战技巧。

第15章,响应式编程基础。本章将介绍响应式系统和响应式编程的基本概念以及应用场景,并分析响应式编程模型所包含的响应式流和背压机制,这是实现系统弹性的关键。

第16章,Project Reactor。本章将介绍目前业界领先的响应式编程框架Project Reactor,它有多种组合方式和完善的异常处理机制,以及面对背压时的处理机制、重试机制。

第17章,WebFlux和RSocket。本章将介绍如何使用Spring中全新的Web开发框架WebFlux来构建响应式RESTful服务,如何使用WebClient工具类来调用响应式服务以及如何使用全新的RSocket协议来实现网络通信中的响应式数据传输。

第18章,响应式Spring Data。本章将讨论如何构建响应式数据访问层,介绍如何使用Spring Data Reactive组件来实现这一目标。MongoDB和Redis都内置了支持响应式数据访问的驱动程序。另外,传统的JDBC并不支持响应式编程模式,但Spring家族也专门提供了Spring Data R2DBC框架来解决这一问题。

第19章,ReactiveSpringCSS:响应式Spring案例实战。本章将提供一个 ReactiveSpringCSS案例来贯穿整个学习过程,内容涉及响应式Web、响应式数据访问、响应式消息通信等主题。在介绍每个主题时,本章会为案例系统添加相应的功能特性。通过完整的案例系统,本章会给出各个组件的具体应用方式和过程,并提供能够直接应用于日常开发的实战技巧。

以上19章内容可以分成4篇,其中第1章作为独立的开篇,对Spring框架进行了概述;第2~7章是Spring Boot篇,第8~14章是Spring Cloud篇,而第15~19章则是响应式编程篇。基于这4篇内容,本书对Spring的技术体系和核心组件进行了全面且系统的阐述,本书主要面向广大服务端开发人员以及对Spring框架有兴趣的开发人员。

感谢我的家人,特别是我的妻子章兰婷女士,对我因撰写本书而大量占用晚上和周末时间的情况,能够给予极大的支持和理解。感谢前公司以及现公司的同事,身处业界领先的公司和团队,我得到很多学习和成长的机会。没有大家平时的帮助,就不可能有这本书的诞生。感谢拉勾教育,感谢人民邮电出版社的武晓燕编辑,这本书能够顺利出版,离不开大家的帮助。

由于作者水平和经验有限,书中难免有欠妥和错误之处,恳请读者批评指正。

郑天民

服务与支持

本书由异步社区出品,社区(https://www.epubit.com/)为您提供后续服务。

您还可以扫码右侧二维码, 关注【异步社区】微信公众号,回复“e59411”直接获取,同时可以获得异步社区15天VIP会员卡,近千本电子书免费畅读。

配套资源

本书提供如下资源:

本书源代码。

要获得以上配套资源,请在异步社区本书页面中点击,跳转到下载界面,按提示进行操作即可。注意:为保证购书读者的权益,该操作会给出相关提示,要求输入提取码进行验证。

提交勘误

作者、译者和编辑尽最大努力来确保书中内容的准确性,但难免会存在疏漏。欢迎您将发现的问题反馈给我们,帮助我们提升图书的质量。

当您发现错误时,请登录异步社区,按书名搜索,进入本书页面,单击“发表勘误”,输入错误信息,单击“提交勘误”按钮即可,如下图所示。本书的作者和编辑会对您提交的错误信息进行审核,确认并接受后,您将获赠异步社区的100积分。积分可用于在异步社区兑换优惠券、样书或奖品。

与我们联系

我们的联系邮箱是contact@epubit.com.cn。

如果您对本书有任何疑问或建议,请您发邮件给我们,并请在邮件标题中注明本书书名,以便我们更高效地做出反馈。

如果您有兴趣出版图书、录制教学视频,或者参与图书翻译、技术审校等工作,可以发邮件给我们;有意出版图书的作者也可以到异步社区投稿(直接访问www.epubit.com/contribute即可)。

如果您所在的学校、培训机构或企业想批量购买本书或异步社区出版的其他图书,也可以发邮件给我们。

如果您在网上发现有针对异步社区出品图书的各种形式的盗版行为,包括对图书全部或部分内容的非授权传播,请您将怀疑有侵权行为的链接通过邮件发送给我们。您的这一举动是对作者权益的保护,也是我们持续为您提供有价值的内容的动力之源。

关于异步社区和异步图书

“异步社区”是人民邮电出版社旗下IT专业图书社区,致力于出版精品IT图书和相关学习产品,为作译者提供优质出版服务。异步社区创办于2015年8月,提供大量精品IT图书和电子书,以及高品质技术文章和视频课程。更多详情请访问异步社区官网https://www.epubit.com。

“异步图书”是由异步社区编辑团队策划出版的精品IT专业图书的品牌,依托于人民邮电出版社的计算机图书出版积累和专业编辑团队,相关图书在封面上印有异步图书的LOGO。异步图书的出版领域包括软件开发、大数据、人工智能、测试、前端、网络技术等。

异步社区

微信服务号

第一篇 Spring概述篇

本篇仅一章,作为开篇总领全书。

本篇从Spring框架的基本概念出发,引出Spring家族生态和技术体系,以及框架所提供的整体定位和解决方案。围绕Spring所具备的各项功能,本篇从Spring Boot与Web应用程序、Spring Cloud与微服务架构、Spring 5与响应式编程等维度进行切入,分别讨论针对不同应用场景的技术体系。这些技术体系也构成了本书其他三篇内容的主体。

第1章 直面Spring

在Java EE领域中,Spring无疑是非常主流的开发框架。Spring是一款集成的开源框架,它整合了很多第三方组件和框架。这些组件和框架应用如此之广泛,以致于大家往往对如何更好地使用Spring自身的功能特性并不是很重视。事实上,Spring自身的功能特性同样非常丰富,而且在使用上也存在一些最佳实践。

本章作为全书的开篇,将对Spring中的基本概念和技术体系做简要介绍,并引出开发人员在使用该框架时所涉及的核心技术组件。本章的最后也会给出全书的组织架构。

1.1 Spring容器

本节讨论Spring容器,并给出容器所具备的非常重要的两个功能特性,即依赖注入和面向切面编程。

1.1.1 IoC

在介绍Spring容器之前,我们先来介绍一个概念,即控制反转(Inversion of Control,IoC)。试想,如果想有效管理一个对象,就需要知道创建、使用以及销毁这个对象的方法。这个过程显然是繁杂而重复的。而通过控制反转,就可以把这部分工作交给一个容器,由容器负责控制对象的生命周期和对象之间的关联关系。这样,与一个对象控制其他对象的处理方式相比,现在所有对象都被容器控制,控制的方向做了一次反转,这就是“控制反转”这一名称的由来。而Spring扮演的角色就是这里的容器。

可以看到控制反转的重点是在系统运行中,按照某个对象的需要,动态提供它所依赖的其他对象,而这一点可以通过依赖注入(Dependency Injection,DI)实现。Spring会在适当的时候创建一个Bean,然后像使用注射器一样把它注入目标对象中,这样就完成了对各个对象之间关系的控制。

可以说,依赖注入是开发人员使用Spring框架的基本手段,我们可以通过依赖注入获取所需的各种Bean。Spring为开发人员提供了3种不同的依赖注入方式,分别是字段注入、构造器注入和Setter方法注入。

现在,假设我们有如下所示的HealthRecordService接口以及它的实现类:

public interface HealthRecordService {
 
     public void recordUserHealthData();
}
 
public class HealthRecordServiceImpl implements HealthRecordService {
 
     @Override
     public void recordUserHealthData () {
          System.out.println("HealthRecordService has been called.");
     }
}

下面我们来讨论具体如何在Spring中完成对HealthRecordServiceImpl实现类的注入,并分析各种注入类型的优缺点。

1.依赖注入的3种方式

首先,我们来看看字段注入,即在一个类中通过字段的方式注入某个对象,如下所示:

public class ClientService {
 
     @Autowired 
     private HealthRecordService healthRecordService;
 
     public void recordUserHealthData() {
          healthRecordService.recordUserHealthData();
     }
}

可以看到,通过@Autowired注解,字段注入的实现方式非常简单而直接,代码的可读性也很高。事实上,字段注入是3种依赖注入方式中最常用、最容易使用的一种。但是,它也是3种注入方式中最应该避免使用的一种。如果使用过IDEA,你可能遇到过这个提示—Field injection is not recommended,告诉你不建议使用字段注入。字段注入的最大问题是对象在外部是不可见的。正如在上面的ClientService类中,我们定义了一个私有变量HealthRecordService来注入该接口的实例。显然,这个实例只能在ClientService类中被访问,脱离了容器环境就无法访问这个实例。

基于以上分析,Spring官方推荐的注入方式实际上是构造器注入。这种注入方式也很简单,就是通过类的构造函数来完成对象的注入,如下所示:

public class ClientService {
 
     private HealthRecordService healthRecordService;
 
     @Autowired 
     public ClientService(HealthRecordService healthRecordService) {
          this.healthRecordService = healthRecordService;
     }
 
     public void recordUserHealthData() {
          healthRecordService.recordUserHealthData();
     }
}

可以看到构造器注入能解决对象外部可见性的问题,因为HealthRecordService是通过ClientService构造函数进行注入的,所以势必可以脱离ClientService而独立存在。构造器注入的显著问题就是当构造函数中存在较多依赖对象时,大量的构造器参数会让代码显得比较冗长。这时就可以使用Setter方法注入。我们同样先来看一下Setter方法注入的实现代码,如下所示:

public class ClientService {
 
     private HealthRecordService healthRecordService;
 
     @Autowired 
     public void setHealthRecordService(HealthRecordService healthRecordService) {
          this.healthRecordService = healthRecordService;
     }
 
     public void recordUserHealthData() {
          healthRecordService.recordUserHealthData();
     }
}

Setter方法注入和构造器注入看上去有些类似,但Setter方法比构造函数更具可读性,因为我们可以把多个依赖对象分别通过Setter方法逐一进行注入。而且,Setter方法注入对于非强制依赖注入很有用,我们可以有选择地注入一部分想要注入的依赖对象。换句话说,可以实现按需注入,帮助开发人员只在需要时注入依赖关系。

作为总结,我们用一句话来概括Spring中所提供的3种依赖注入方式:构造器注入适用于强制对象注入;Setter方法注入适用于可选对象注入;而字段注入是应该避免的,因为对象无法脱离容器而独立运行。

2.Bean的作用域

所谓Bean的作用域,描述了Bean在Spring容器上下文中的生命周期和可见性。在这里,我们将讨论Spring框架中不同类型的Bean的作用域以及使用上的指导规则。

如果想要通过注解来设置Bean的作用域,可以使用如下所示的代码:

@Configuration
public class AppConfig {
     
     @Bean
     @Scope("singleton")
     public HealthRecordService createHealthRecordService() {
          return new HealthRecordServiceImpl();
     }
}

可以看到这里使用了一个@Scope注解来指定Bean的作用域为单例的“singleton”。在Spring中,除了单例作用域之外,还有一个“prototype”,即原型作用域,也可以称为多例作用域来与单例作用域进行区别。在使用方式上,我们同样可以使用如下所示的枚举值来对它们进行设置:

@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) 
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)

在Spring IoC容器中,Bean的默认作用域是单例作用域,也就是说不管对Bean的引用有多少个,容器只会创建一个实例。而原型作用域则不同,每次请求Bean时,Spring IoC容器都会创建一个新的对象实例。

从两种作用域的效果而言,我们总结一条开发上的结论,即对于无状态的Bean,我们应该使用单例作用域,反之则应该使用原型作用域。

那么,什么样的Bean属于有状态的呢?结合Web应用程序,我们可以明确,对每次HTTP请求而言,都应该创建一个Bean来代表这一次的请求对象。同样,对会话而言,我们也需要针对每个会话创建一个会话状态对象。这些都是常见的有状态的Bean。为了更好地管理这些Bean的生命周期,Spring还专门针对Web开发场景提供了对应的“request”和“session”作用域。

1.1.2 AOP

在本小节中,我们将讨论Spring容器的另一项核心功能,即面向切面编程(Aspect Oriented Programming,AOP)。我们将介绍AOP的概念以及实现这些概念的方法。

所谓切面,本质上解决的是关注点分离的问题。在面向对象编程的世界中,我们把一个应用程序按照职责和定位拆分成多个对象,这些对象构成了不同的层次。而AOP可以说是面向对象编程的一种补充,目标是将一个应用程序抽象成各个切面。

举个例子,假设一个Web应用中存在ServiceA、ServiceB和ServiceC这3个服务,而每个服务都需要考虑安全校验、日志记录、事务处理等非功能性需求。这时,就可以引入AOP的思想把这些非功能性需求从业务需求中拆分出来,构成独立的关注点,如图1-1所示。

图1-1 AOP的思想示意

从图1-1可以很形象地看出,所谓切面相当于应用对象间的横切面,我们可以将其抽象为单独的模块进行开发和维护。

为了理解AOP的具体实现过程,我们需要引入一组特定的术语,具体如下。

连接点(Join Point):连接点表示应用执行过程中能够插入切面的一个点。这种连接点可以是方法调用、异常处理、类初始化或对象实例化。在Spring框架中,连接点只支持方法的调用。

通知(Advice):通知描述了切面何时执行以及如何执行对应的业务逻辑。通知有很多种类型,在Spring中提供了一组注解用来表示通知,包括@Before、@After、@Around、@AfterThrowing和@AfterReturning等。我们会在后续代码示例中看到这些注解的使用方法。

切点(Point Cut):切点是连接点的集合,用于定义必须执行的通知。通知不一定应用于所有连接点,因此切点提供了在应用程序中的组件上执行通知的细粒度控制。在Spring中,可以通过表达式来定义切点。

切面(Aspect):切面是通知和切点的组合,用于定义应用程序中的业务逻辑及其应执行的位置。Spring提供了@Aspect注解来定义切面。

现在,假设有这样一个代表转账操作的TransferService接口:

public interface TransferService {
 
     boolean transfer(Account source, Account dest, int amount) throws MinimumAmountException;
}

然后我们提供它的实现类:

package com.demo;
 
public class TransferServiceImpl implements TransferService {
 
     private static final Logger LOGGER = Logger.getLogger(TransferServiceImpl.class);
 
     @Override
     public boolean transfer(Account source, Account dest, int amount) throws MinimumAmountException { 
          LOGGER.info("Tranfering " + amount + " from " + source.getAccountName() + " to " + dest.getAccountName());
 
          if (amount < 10) {
               throw new MinimumAmountException("转账金额必须大于10");
          }
          return true;
     }
}

针对转账操作,我们希望在该操作之前、之后以及执行过程进行切入,并添加对应的日志记录,那么可以实现如下所示的TransferServiceAspect类:

@Aspect
public class TransferServiceAspect {
 
     private static final Logger LOGGER = Logger.getLogger(TransferServiceAspect.class);
 
     @Pointcut("execution(* com.demo.TransferService.transfer(..))")
     public void transfer() {}
 
     @Before("transfer()")
     public void beforeTransfer(JoinPoint joinPoint) {
          LOGGER.info("在转账之前执行");
     }
 
     @After("transfer()")
     public void afterTransfer(JoinPoint joinPoint) {
          LOGGER.info("在转账之后执行");
     }
 
     @AfterReturning(pointcut = "transfer() and args(source, dest, amount)", returning = "isTransferSucessful")
     public void afterTransferReturns(JoinPoint joinPoint, Account source, Account dest, Double amount, boolean isTransferSucessful) {
          if (isTransferSucessful) {
               LOGGER.info("转账成功了");
          }
     }
     
     @AfterThrowing(pointcut = "transfer()", throwing = "minimumAmountException")
     public void exceptionFromTransfer(JoinPoint joinPoint, MinimumAmountException minimumAmountException) {
          LOGGER.info("转账失败了:" + minimumAmountException.getMessage());
     }
     
     @Around("transfer()")
     public boolean aroundTransfer(ProceedingJoinPoint proceedingJoinPoint){
          LOGGER.info("方法执行之前调用");
          boolean isTransferSuccessful = false;
          try {
               isTransferSuccessful = (Boolean)proceedingJoinPoint.proceed();
          } catch (Throwable e) {
               LOGGER.error(e.getMessage(), e);
          }
          LOGGER.info("方法执行之后调用");
          return isTransferSuccessful;
     }
}

上述代码代表了Spring AOP机制的典型使用方法。使用@Pointcut注解定义了一个切入点,并通过“execution”指示器限定该切入点匹配的包结构为“com.demo”,匹配的方法是TransferService类的transfer()方法。

请注意,在TransferServiceAspect中综合使用了@Before、@After、@Around、@AfterThrowing和@AfterReturning注解用来设置5种不同类型的通知。其中@Around注解会将目标方法封装起来,并执行动态添加返回值、异常信息等操作。这样@AfterThrowing和@AfterReturning注解就能获取这些返回值或异常信息并做出响应,而@Before和@After注解可以在方法调用的前后分别添加自定义的处理逻辑。

1.2 Spring家族生态

Spring框架自2003年由Rod Johnson设计并实现以来,经历了多个重大版本的发展和演进,已经形成了一个庞大的“家族式技术生态圈”。目前,Spring已经是Java EE领域非常流行的开发框架,在全球各大企业中都得到了广泛应用。本节将梳理整个Spring家族中的技术体系,以及各种功能齐全的开发框架。

让我们通过Spring的官方网站来看一下Spring家族技术生态的全景图,如图1-2所示。

可以看到,这里罗列了Spring框架的七大核心技术体系,分别是微服务架构、响应式编程、云原生、Web应用、Serverless架构、事件驱动以及批处理。

一方面,这些技术体系各自独立但也有一定交集,例如微服务架构往往会与基于Spring Cloud的云原生技术结合在一起使用,而微服务架构的构建过程也需要依赖于能够提供RESTful风格的Web应用程序等。

另一方面,除了具备特定的技术特点,这些技术体系也各有其应用场景。例如,如果我们想要实现日常报表等轻量级的批处理任务,而又不想引入Hadoop这套庞大的离线处理平台,那么使用基于Spring Batch的批处理框架是一个不错的选择。再比方说,如果想要实现与Kafka、RabbitMQ等各种主流消息中间件的集成,但又希望开发人员不需要了解这些中间件在使用上的差别,那么使用基于Spring Cloud Stream的事件驱动架构是首选,因为这个框架对外提供了统一的API,从而屏蔽了内部各个中间件在实现上的差异性。

图1-2 Spring家族技术体系(来自Spring官网)

当然,所有我们现在能看到的Spring家族技术体系都是在Spring Framework的基础上逐步演进而来的。在介绍上述技术体系之前,我们先简单对其进行回顾。Spring Framework的整体架构如图1-3所示。

图1-3 Spring Framework的整体架构

Spring从诞生之初就被认为是一种容器,图1-3中的核心容器部分就包含一个容器所应该具备的核心功能,涉及1.1节中介绍的基于依赖注入机制的Bean、AOP、Context,以及Spring自身所提供的表达式工具Instrument等一些辅助功能。

图1-3最上面的就是构建应用程序所需要的两大核心功能组件,也是我们日常开发中最常用的组件,即数据访问和Web服务。这两大功能组件中包含的内容非常多,而且充分体现了Spring Framework的集成性。也就是说,框架内部整合了业界主流的数据库驱动、消息中间件、ORM框架等各种工具,开发人员可以根据需要灵活地替换和调整自己想要使用的工具。

从开发语言上讲,虽然Spring最广泛的一个应用场景是在Java EE领域,但在最新的版本中也支持Kotlin、Groovy以及各种动态开发语言。

本书无意对Spring中的所有七大技术体系做全面的展开。在日常开发过程中,如果要构建单块Web服务,可以采用Spring Boot。如果想要开发微服务架构,那么需要使用基于Spring Boot的Spring Cloud,而Spring Cloud同样内置了基于Spring Cloud Stream的事件驱动架构。同时,在这里应特别强调的是响应式编程技术。响应式编程是Spring 5引入的最大创新,代表了一种系统架构设计和实现的技术方向。因此,本书也将从Spring Boot、Spring Cloud以及Spring响应式编程这三大技术体系进行切入,看看Spring具体能够为我们解决开发过程中的哪些问题。

1.3 Spring Boot与Web应用程序

前面提到Spring家族具备多款开源框架,开发人员可以基于这些开发框架实现各种Spring应用程序。在本节中,我们关注的是基于Spring Boot开发面向Web场景的服务,这也是互联网应用程序最常见的表现形式之一。

1.3.1 剖析一个Spring Web应用程序

在介绍基于Spring Boot的开发模式之前,让我们先将它与传统的Spring MVC进行对比。

1.Spring MVC vs Spring Boot

在典型的Web应用程序中,前后端通常基于HTTP完成请求和响应,开发过程中需要完成HTTP请求的构建、URL地址的映射、对象的序列化和反序列化以及实现各个服务自身内部的业务逻辑,如图1-4所示。

图1-4 HTTP请求和响应过程

我们先来看基于Spring MVC的Web应用程序开发流程,如图1-5所示。

图1-5 基于Spring MVC的Web应用程序开发流程

图1-5包括使用web.xml定义Spring的DispatcherServlet、完成启动Spring MVC的配置文件、编写响应HTTP请求的控制器(Controller),以及部署服务到Web服务器等流程。事实上,基于传统的Spring MVC框架开发Web应用程序逐渐暴露出一些问题,比较典型的就是配置工作过于复杂和繁重,以及缺少必要的应用程序管理和监控机制。

如果想要优化这一套开发流程,有几个点值得我们去挖掘,比方说减少不必要的配置工作、启动依赖项的自动管理、简化部署并提供应用监控等。这些优化点推动了以Spring Boot为代表的新一代开发框架的诞生。基于Spring Boot的Web应用程序开发流程如图1-6所示。

图1-6 基于Spring Boot的Web应用程序开发流程

从图1-6可以看到,它与基于Spring MVC的Web应用程序开发流程在配置信息的管理、服务部署和监控等方面有明显不同。作为Spring家族新的一员,Spring Boot提供了令人兴奋的特性,这些特性的核心价值就是确保了开发过程的简单性,具体体现在编码、配置、部署、监控等多个方面。

Spring Boot使编码更简单。

我们只需要在Maven中添加一项依赖并实现一个Controller,就可以提供微服务架构中所推崇的RESTful风格接口。

Spring Boot使配置更简单。

它把Spring中基于XML的功能配置方式转换为Java Config,同时提供了.yml文件来优化原有的基于.properties和.xml文件的配置方案。.yml文件对配置信息的组织更为直观、方便,语义也更为强大。同时,基于自动配置特性,Spring Boot对常见的各种工具和框架均提供了默认的starter组件来简化配置。

Spring Boot使部署更简单。

在部署方案上,Spring Boot也创造了一键启动的新模式。相较于传统模式下的war包,Spring Boot部署包既包含业务代码和各种第三方类库,同时也内嵌HTTP容器。这种包结构支持java–jar命令方式的一键启动,它不需要部署独立的应用服务器,通过默认的内嵌Tomcat就可以运行整个应用程序。

Spring Boot使监控更简单。

相较于传统的Spring框架,Spring Boot的一大亮点是引入了内置的监控机制,这是通过Actuator组件来实现的。基于Actuator组件,我们可以查看包含自动配置在内的应用程序的详细信息。另一方面,也可以实时监控应用程序的运行时健康状态。这部分信息中常见的包括内存信息、JVM信息、垃圾回收信息等。例如,可以通过“/env/{name}”端点获取系统环境变量、通过“/mapping”端点获取所有RESTful服务、通过“/dump”端点获取线程工作状态,以及通过“/metrics/{name}”端点获取JVM性能指标等。

2.基于Spring Boot的Web应用程序开发

针对一个基于Spring Boot开发的Web应用程序,其代码组织方式需要遵循一定的项目结构。在本书中,如果不做特殊说明,我们都将使用Maven来管理项目中的结构和包依赖。一个典型的Web应用程序的项目结构包括包依赖、启动类、Controller类以及配置文件等4个组成部分。

包依赖。

Spring Boot提供了一系列starter组件来简化各种组件之间的依赖关系。以开发Web应用程序为例,我们需要引入spring-boot-starter-web这个组件,而这个组件中并没有具体的代码,而只包含一些依赖,如下所示:

org.springframework.boot:spring-boot-starter
org.springframework.boot:spring-boot-starter-tomcat
org.springframework.boot:spring-boot-starter-validation
com.fasterxml.jackson.core:jackson-databind
org.springframework:spring-web
org.springframework:spring-webmvc

可以看到,这里包括传统Spring MVC应用程序中会使用到的spring-web和spring-webmvc组件,因此Spring Boot在底层实现上还是基于这两个组件完成对Web请求响应流程的构建的。

在应用程序中引入spring-boot-starter-web组件就像引入一个普通的Maven依赖,如下所示:

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
</dependency>

一旦spring-boot-starter-web组件引入完毕,我们就可以充分利用Spring Boot提供的自动配置机制开发Web应用程序。

启动类。

使用Spring Boot的非常重要的一个步骤是创建一个Bootstrap启动类。Bootstrap类结构简单且比较固化,如下所示:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@SpringBootApplication
public class HelloApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(HelloApplication.class, args);
    }
}

可以看到,这里引入了一个全新的注解@SpringBootApplication。在Spring Boot中,添加了该注解的类就是整个应用程序的入口,一方面会启动Spring容器,另一方面也会自动扫描代码包结构下的@Component、@Service、@Repository、@Controller等注解,并把这些注解对应的类转化为Bean对象,从而全部加载到Spring容器中。

Controller类。

Bootstrap类为我们提供了Spring Boot应用程序的入口,相当于应用程序已经具备最基本的骨架。接下来我们就可以添加HTTP请求的访问入口,表现在Spring Boot中就是一系列的Controller类。这里的Controller与Spring MVC中的Controller在概念上是一致的。一个典型的Controller类如下所示:

@RestController
@RequestMapping(value = "accounts")
public class AccountController {
 
     @Autowired 
     private AccountService accountService;
 
     @GetMapping(value = "/{accountId}")
     public Account getAccountById(@PathVariable("accountId") Long accountId) {
          Account account = accountService.getAccountById(accountId);
          return account;
     }
}

请注意,以上代码中包含@RestController、@RequestMapping和@GetMapping这3个注解。其中,@RequestMapping用于指定请求地址的映射关系,@GetMapping的作用等同于指定了GET请求方法的@RequestMapping注解。而@RestController注解是传统Spring MVC中所提供的@Controller注解的升级版,相当于@Controller和@ResponseEntity这两个注解的结合体,会自动使用JSON实现序列化/反序列化操作。

配置文件。

注意到在src/main/resources目录下存在一个application.yml文件,这就是Spring Boot中的默认配置文件。例如,我们可以将如下所示的端口、服务名称以及数据库访问等配置信息添加到这个配置文件中:

server:
  port: 8081
 
spring:
  application:
    name: orderservice 
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/appointment
    username: root
password: root

事实上,Spring Boot提供了强大的自动配置机制,如果没有特殊的配置需求,开发人员完全可以基于Spring Boot内置的配置体系完成诸如数据库访问相关配置信息的自动集成。

1.3.2 Spring Boot中的技术组件

Spring Boot构建在Spring Framework的基础之上,是新一代的Web应用程序开发框架。我们可以通过图1-7来了解Spring Boot的全貌。

图1-7 Spring Boot整体架构

通过浏览Spring的官方网站,我们可以看到Spring Boot已经成为Spring中最顶级的子项目之一。自2014年4月发布1.0.0版本以来,Spring Boot俨然已经发展为Java EE领域开发Web应用程序的首选框架。

通过前面的描述,可以看到Spring Boot中一个传统Spring框架所不具备的功能特性,就是支持运行时内嵌容器,包含Tomcat、Jetty等支持Servlet规范的多款传统Web容器可供开发人员选择。而在最新的Spring Boot 2.x中,还提供了对Netty以及集成Servlet 3.1+的非阻塞式容器的支持。基于运行时内嵌容器机制,开发人员只需要使用一行java–jar命令就可以启动Web服务了。

另一个通过前面的示例可以看到的功能特性就是自动配置。前面的示例并没有像以前使用Spring MVC一样指定一大堆关于HTTP请求和响应的XML配置。事实上,Spring Boot的运行过程同样还是依赖于Spring MVC,但是它把原本需要开发人员指定的各种配置项设置了默认值并内置在运行时环境中,例如默认的服务器端口就是8080。如果我们对这些配置项没有定制化需求,就可以不做任何的处理,采用既定的开发约定即可。这就是Spring Boot所倡导的约定优于配置(Convention over Configuration)的设计理念。

1.4 Spring Cloud与微服务架构

在本节中,我们关注的是基于Spring Cloud开发面向微服务的系统,这也是当下非常主流的一种构建分布式系统的技术体系。

1.4.1 从Spring Boot到Spring Cloud

Spring Cloud具备一个天生的优势,那就是它是Spring家庭的一员,而Spring在Java EE开发领域的强大地位给Spring Cloud起到了很好的推动作用。同时,Spring Cloud基于Spring Boot,而Spring Boot已经成为Java EE领域中最流行的开发框架之一,Spring Cloud被用来简化Spring应用程序的框架搭建和开发过程。Spring Cloud与微服务架构如图1-8所示。

图1-8 Spring Cloud与微服务架构(来自Spring官网)

在微服务架构中,我们将使用Spring Boot来开发单个微服务。同样作为Spring家族新的一员,Spring Boot提供了令人兴奋的特性。正如我们在1.3节中所讨论的,这些特性主要体现在开发过程的简单化,包括支持快速构建项目、不依赖外部容器独立运行、开发部署效率高以及与云平台天然集成等。而在微服务架构中,Spring Cloud构建在Spring Boot之上,继承了Spring Boot配置简单、开发快速、部署轻松的特点,让原本复杂的架构工作变得相对容易上手。

1.4.2 Spring Cloud中的技术组件

技术组件的完备性是我们选择Spring Cloud的主要原因。Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了微服务系统基础设施的开发过程,如服务发现注册、API网关、配置中心、消息总线、负载均衡、熔断器、数据监控等都可以基于Spring Boot的开发风格做到一键启动和部署。

在对微服务的各项技术组件进行设计和实现的过程中,Spring Cloud也有自己的一些特色。一方面,它对微服务架构开发所需的技术组件进行了抽象,提供了符合开发需求的独立组件,包括用于配置中心的Spring Cloud Config、用于API网关的Spring Cloud Gateway等。另一方面,Spring Cloud也没有“重复造轮子”,它将目前各家公司现有的比较成熟、经得起实践考验的服务框架组合起来,通过Spring Boot开发风格进行了再次封装。这部分主要指的是Spring Cloud Netflix组件,其中集成了Netflix OSS的Eureka注册中心、Hystrix熔断器、Zuul网关等工具,如图1-9所示。

图1-9 Spring Cloud、Spring Cloud Netflix与Netflix OSS之间的关系

Spring Cloud屏蔽了微服务架构开发所需的复杂配置和实现过程,最终给开发者提供了一套易理解、易部署和易维护的开发工具包。Spring Cloud中的组件非常多,本书无意对所有组件都进行详细展开,而是梳理了开发一个微服务系统所必需的八大核心组件,如图1-10所示。

图1-10 Spring Cloud核心功能组件

可以看到,基于Spring Boot的开发便利性,Spring Cloud巧妙地简化了微服务系统基础设施的开发过程。

1.5 Spring 5与响应式编程

无论是电商类系统,还是互联网场景下的智能终端平台,都面临着大流量、高并发的访问请求。在各种请求压力下,系统就可能出现一系列可用性问题,作为系统的设计者,需要保证系统拥有即时的响应性。如何时刻确保系统具有应对请求压力的弹性,成为一个非常现实且棘手的问题。响应式编程技术针对这类问题提供了一种新的解决方案。

1.5.1 响应式编程技术

经典的服务隔离、限流、降级以及熔断等机制能够在一定程度上实现系统的弹性。通过对比更多可选的技术体系之后,可发现构建系统弹性的一种崭新的解决方案,这就是响应式编程。响应式编程打破了传统的同步阻塞式编程模型,基于响应式数据流和背压机制实现了异步非阻塞式的网络通信、数据访问和事件驱动架构,能够缓解服务器资源的竞争,从而提高服务的响应能力。

比方说,当系统中的服务A需要访问服务B时,在服务A发出请求之后,执行线程会等待服务B的返回,这段时间该线程就是阻塞的,因此整个过程的CPU利用效率低下,很多时间线程被浪费在了I/O阻塞上。更进一步,当执行数据访问时,数据库的执行操作也面临着同样的阻塞式问题。这样,整个请求链路的各个环节都会导致资源的浪费,从而降低系统的弹性。而通过引入响应式编程技术,就可以很好地解决这种类型的问题。

事实上,很多开发框架中已经应用了响应式编程技术。在1.4节中提到的Spring Cloud中存在的Netflix Hystrix组件,就是专门用来实现服务限流的熔断器组件。在这个组件中,实现了一个HealthCountsStream类来提供滑动窗口机制,从而完成对运行时请求数据的动态收集和处理。Hystrix在实现这一机制时大量采用了数据流处理方面的技术以及RxJava响应式编程框架。

再比方说,针对Spring Cloud,Spring家族还专门开发了一个网关工具Spring Cloud Gateway。相比Netflix中提供的基于同步阻塞式模型的Zuul网关,Spring Cloud Gateway的性能得到了显著的提升,因为它采用了异步非阻塞式的实现机制,而这一机制正是借助于响应式编程框架Project Reactor以及Spring 5中所内嵌的相关开发技术实现的。

1.5.2 响应式Spring中的技术组件

你可能会问,如何应用响应式编程技术呢?它的开发过程是不是很有难度呢?这点不用担心,因为随着Spring 5的正式发布,我们迎来了响应式编程的全新发展时期。Spring 5中内嵌了与数据管理相关的响应式数据访问、与系统集成相关的响应式消息通信以及与Web服务相关的响应式Web框架等多种响应式组件,从而极大简化了响应式应用程序的开发过程和降低了相应的开发难度。图1-11展示了响应式编程技术栈与传统的Servlet技术栈之间的对比。

图1-11 响应式编程技术栈与传统的Servlet技术栈之间的对比(来自Spring官网)

可以看到,图1-11左侧为基于Spring WebFlux的技术栈,右侧为基于Spring MVC的技术栈。我们知道传统的Spring MVC构建在Java EE的Servlet标准之上,该标准本身就是阻塞式和同步的。而Spring WebFlux基于响应式流,因此可以用来构建异步非阻塞的服务。

在Spring 5中,选取了Project Reactor作为响应式流的实现库。由于响应式编程的特性,Spring WebFlux和Reactor的运行需要依赖于诸如Netty和Undertow等支持异步机制的容器。也可以选择使用较新版本的Tomcat和Jetty作为运行环境,因为它们支持异步I/O的Servlet 3.1。图1-12更加明显地展示了Spring MVC和Spring WebFlux的区别和联系。

在基于Spring Boot以及Spring Cloud的应用程序中,Spring WebFlux和Spring MVC可以混合进行使用。

另一方面,针对数据访问,从Spring Boot 2开始,对于那些支持响应式访问的数据库,Spring Data也提供了响应式版本的Repository支持。我们可以使用MongoDB和Redis等NoSQL数据库来实现响应式数据访问。

图1-12 Spring MVC和Spring WebFlux的区别和联系

1.6 全书架构

图1-13归纳了本书内容的组织架构。本章作为全书的第1章,引入了Spring这款主流的开源开发框架,而剩下的章节在组织上按照Spring Boot篇→Spring Cloud篇→响应式Spring篇来展开。

图1-13 全书组织架构

首先,“Spring Boot篇”介绍Spring Boot所具备的核心功能特性,包括配置体系、数据访问、Web服务、消息通信和系统监控。这些功能是使用Spring框架的基本入口,可以说开发一个典型的Web应用程序离不开这些功能,后续介绍Spring Cloud和响应式Spring时,也需要依赖于这部分功能特性。在本篇的最后,我们从零开始构建一个SpringCSS案例系统,并将这些功能特性应用到具体的开发过程中。

“Spring Cloud篇”中的功能用于构建当下主流的微服务架构。本篇讨论了Spring家族中的Spring Cloud框架在面向分布式环境下的应用场景,详细介绍用于构建一个微服务系统的注册中心、服务网关、服务容错、配置中心、消息通信、服务监控等核心组件。这些组件都是开发一个微服务系统所必备的功能组件。在本篇的最后,我们同样从零开始构建一个SpringHealth案例系统,并将这些功能特性应用到具体的开发过程中。

最后,“响应式Spring篇”的内容关注Spring 5中新引入的响应式编程技术。响应式编程代表一种技术趋势,可以用来构建异步非阻塞的系统架构。这一篇对响应式编程的基础概念、响应式编程框架Project Reactor、响应式WebFlux和RSocket、响应式Spring Data等技术体系全面展开,理论联系实际,阐述Spring框架中针对响应式编程所提供的解决方案。同样,在本篇的最后,我们对SpringCSS案例系统做重构和升级并实现了ReactiveSpringCSS案例系统,用来展示响应式编程技术的具体落地方案和实现技巧。

1.7 本章小结

本章作为全书的第1章,全面介绍了Spring框架的各个方面以及本书对Spring框架所采用的讲解思路,并对Spring Boot的开发模式和所提供的各项技术组件做了介绍。相较于传统的Spring框架,Spring Boot在编码、配置、部署、监控等方面都做了优化。同时,本章正式引入了Spring家族中的微服务开发框架Spring Cloud,明确了Spring Cloud是构建在Spring Boot之上,且提供了一系列的核心组件用来满足微服务系统的开发需求。最后,本章介绍了Spring 5所提供的响应式编程技术,同样也分析了Spring为开发人员准备的各项技术体系。

读者服务:

微信扫码关注【异步社区】微信公众号,回复“e59411”获取本书配套资源以及异步社区15天VIP会员卡,近千本电子书免费畅读。

第二篇 Spring Boot篇

本篇共有6章,全面介绍Spring Boot框架所具备的功能特性,并基于这些功能特性构建一个简单而完整的案例系统。在Java EE领域中,Spring Boot作为Spring家族中的一员,在传统Spring框架的基础上做了创新和优化,将开发人员从以往烦琐的配置工作中解放出来,并提供了大量的即插即用的集成化组件,从而解决开发过程中各种组件之间复杂的整合问题,提高了开发效率,降低了维护成本。本篇包括第2~7章。

相关图书

深入浅出Spring Boot 3.x
深入浅出Spring Boot 3.x
云原生Spring实战Spring Boot与?Kubernetes实践
云原生Spring实战Spring Boot与?Kubernetes实践
Spring实战(第6版)
Spring实战(第6版)
Java研发自测入门与进阶
Java研发自测入门与进阶
Java EE企业级应用开发实战(Spring Boot+Vue+Element)
Java EE企业级应用开发实战(Spring Boot+Vue+Element)
Spring Boot源码解读与原理分析
Spring Boot源码解读与原理分析

相关文章

相关课程