CategoryResourceRepost/极客时间专栏/设计模式之美/开源与项目实战:开源实战/84 | 开源实战四(上):剖析Spring框架中蕴含的经典设计思想或原则.md
louzefeng d3828a7aee mod
2024-07-11 05:50:32 +00:00

107 lines
13 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<audio id="audio" title="84 | 开源实战四剖析Spring框架中蕴含的经典设计思想或原则" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/fa/81/fa02986ea66c4b22819ced4499311b81.mp3"></audio>
在Java世界里Spring框架已经几乎成为项目开发的必备框架。作为如此优秀和受欢迎的开源项目它是我们源码阅读的首选材料之一不管是设计思想还是代码实现都有很多值得我们学习的地方。接下来我们就详细讲讲Spring框架中蕴含的设计思想、原则和模式。因为内容比较多我分三部分来讲解。
- 第一部分我们讲解Spring框架中蕴含的经典设计思想或原则。
- 第二部分我们讲解Spring框架中用来支持扩展的两种设计模式。
- 第三部分我们总结罗列Spring框架中用到的其他十几种设计模式。
今天我们就讲下第一部分Spring框架中蕴含的一些设计思想或原则这其中就包括约定大于配置、低侵入松耦合、模块化轻量级等。这些设计思想都很通用掌握之后我们可以借鉴用到其他框架的开发中。
话不多少,让我们正式开始今天的学习吧!
## Spring框架简单介绍
考虑到你可能不熟悉Spring我这里对它做下简单介绍。我们常说的Spring框架是指Spring Framework基础框架。Spring Framework是整个Spring生态也被称作Spring全家桶的基石。除了Spring FrameworkSpring全家桶中还有更多基于Spring Framework开发出来的、整合更多功能的框架比如Spring Boot、Spring Cloud。
在Spring全家桶中Spring Framework是最基础、最底层的一部分。它提供了最基础、最核心的IOC和AOP功能。当然它包含的功能还不仅如此还有其他比如事务管理Transactions、MVC框架Spring MVC等很多功能。下面这个表格是我从Spring官网上找的关于Spring Framework的功能介绍你可以大略地看下有个印象。
<img src="https://static001.geekbang.org/resource/image/1a/41/1ab07ad6aed0f06cbce9547552281041.jpeg" alt="">
在Spring Framework中Spring MVC出镜率很高经常被单独拎出来使用。它是支持Web开发的MVC框架提供了URL路由、Session管理、模板引擎等跟Web开发相关的一系列功能。
Spring Boot是基于Spring Framework开发的。它更加专注于微服务开发。之所以名字里带有“Boot”一词跟它的设计初衷有关。Spring Boot的设计初衷是快速启动一个项目利用它可以快速地实现一个项目的开发、部署和运行。Spring Boot支持的所有功能都是围绕着这个初衷设计的比如集成很多第三方开发包、简化配置比如规约优于配置、集成内嵌Web容器比如Tomcat、Jetty等。
单个的微服务开发使用Spring Boot就足够了但是如果要构建整个微服务集群就需要用到Spring Cloud了。Spring Cloud主要负责微服务集群的服务治理工作包含很多独立的功能组件比如Spring Cloud Sleuth调用链追踪、Spring Cloud Config配置中心等。
## 从Spring看框架的作用
如果你使用过一些框架来做开发你应该能感受到使用框架开发的优势。这里我稍微总结一下。利用框架的好处有解耦业务和非业务开发、让程序员聚焦在业务开发上隐藏复杂实现细节、降低开发难度、减少代码bug实现代码复用、节省开发时间规范化标准化项目开发、降低学习和维护成本等等。实际上如果要用一句话来总结一下的话那就是简化开发
对于刚刚的总结,我们再详细解释一下。
相比单纯的CRUD业务代码开发非业务代码开发要更难一些。所以将一些非业务的通用代码开发为框架在项目中复用除了节省开发时间之外也降低了项目开发的难度。除此之外框架经过多个项目的多次验证比起每个项目都重新开发代码的bug会相对少一些。而且不同的项目使用相同的框架对于研发人员来说从一个项目切换到另一个项目的学习成本也会降低很多。
接下来我们再拿常见的Web项目开发来举例说明一下。
通过在项目中引入Spring MVC开发框架开发一个Web应用我们只需要创建Controller、Service、Repository三层类在其中填写相应的业务代码然后做些简单的配置告知框架Controller、Service、Repository类之间的调用关系剩下的非业务相关的工作比如对象的创建、组装、管理请求的解析、封装URL与Controller之间的映射都由框架来完成。
不仅如此如果我们直接引入功能更强大的Spring Boot那将应用部署到Web容器的工作都省掉了。Spring Boot内嵌了Tomcat、Jetty等Web容器。在编写完代码之后我们用一条命令就能完成项目的部署、运行。
## Spring框架蕴含的设计思想
在Google Guava源码讲解中我们讲到开发通用功能模块的一些比较普适的开发思想比如产品意识、服务意识、代码质量意识、不要重复早轮子等。今天我们剖析一下Spring框架背后的一些经典设计思想或开发技巧。这些设计思想并非Spring独有都比较通用能借鉴应用在很多通用功能模块的设计开发中。这也是我们学习Spring源码的价值所在。
### 1.约定优于配置
在使用Spring开发的项目中配置往往会比较复杂、繁琐。比如我们利用Spring MVC来开发Web应用需要配置每个Controller类以及Controller类中的接口对应的URL。
如何来简化配置呢一般来讲有两种方法一种是基于注解另一种是基于约定。这两种配置方式在Spring中都有用到。Spring在最小化配置方面做得淋漓尽致有很多值得我们借鉴的地方。
基于注解的配置方式我们在指定类上使用指定的注解来替代集中的XML配置。比如我们使用@RequestMapping注解在Controller类或者接口上标注对应的URL使用@Transaction注解表明支持事务等。
基于约定的配置方式也常叫作“约定优于配置”或者“规约优于配置”Convention over Configuration。通过约定的代码结构或者命名来减少配置。说直白点就是提供配置的默认值优先使用默认值。程序员只需要设置那些偏离约定的配置就可以了。
比如在Spring JPA基于ORM框架、JPA规范的基础上封装的一套JPA应用框架我们约定类名默认跟表名相同属性名默认跟表字段名相同String类型对应数据库中的varchar类型long类型对应数据库中的bigint类型等等。
基于刚刚的约定代码中定义的Order类就对应数据库中的“order”表。只有在偏离这一约定的时候例如数据库中表命名为“order_info”而非“order”我们才需要显示地去配置类与表的映射关系Order类-&gt;order_info表
实际上约定优于配置很好地体现了“二八法则”。在平时的项目开发中80%的配置使用默认配置就可以了只有20%的配置必须用户显式地去设置。所以,基于约定来配置,在没有牺牲配置灵活性的前提下,节省了我们大量编写配置的时间,省掉了很多不动脑子的纯体力劳动,提高了开发效率。除此之外,基于相同的约定来做开发,也减少了项目的学习成本和维护成本。
### 2.低侵入、松耦合
框架的侵入性是衡量框架好坏的重要指标。所谓低侵入指的是,框架代码很少耦合在业务代码中。低侵入意味着,当我们要替换一个框架的时候,对原有的业务代码改动会很少。相反,如果一个框架是高度侵入的,代码高度侵入到业务代码中,那替换成另一个框架的成本将非常高,甚至几乎不可能。这也是一些长期维护的老项目,使用的框架、技术比较老旧,又无法更新的一个很重要的原因。
实际上低侵入是Spring框架遵循的一个非常重要的设计思想。
Spring提供的IOC容器在不需要Bean继承任何父类或者实现任何接口的情况下仅仅通过配置就能将它们纳入进Spring的管理中。如果我们换一个IOC容器也只是重新配置一下就可以了原有的Bean都不需要任何修改。
除此之外Spring提供的AOP功能也体现了低侵入的特性。在项目中对于非业务功能比如请求日志、数据采点、安全校验、事务等等我们没必要将它们侵入进业务代码中。因为一旦侵入这些代码将分散在各个业务代码中删除、修改的成本就变得很高。而基于AOP这种开发模式将非业务代码集中放到切面中删除、修改的成本就变得很低了。
### 3.模块化、轻量级
我们知道十几年前EJB是Java企业级应用的主流开发框架。但是它非常臃肿、复杂侵入性、耦合性高开发、维护和学习成本都不低。所以为了替代笨重的EJBRod Johnson开发了一套开源的Interface21框架提供了最基本的IOC功能。实际上Interface21框架就是Spring框架的前身。
但是随着不断的发展Spring现在也不单单只是一个只包含IOC功能的小框架了它显然已经壮大成了一个“平台”或者叫“生态”包含了各种五花八门的功能。尽管如此但它也并没有重蹈覆辙变成一个像EJB那样的庞大难用的框架。那Spring是怎么做到的呢
这就要归功于Spring的模块化设计思想。我们先看一张图如下所示它是Spring Framework的模块和分层介绍图。
<img src="https://static001.geekbang.org/resource/image/69/2c/699208dbe6b43ee397a020ea733c342c.png" alt="">
从图中我们可以看出Spring在分层、模块化方面做得非常好。每个模块都只负责一个相对独立的功能。模块之间关系仅有上层对下层的依赖关系而同层之间以及下层对上层几乎没有依赖和耦合。除此之外在依赖Spring的项目中开发者可以有选择地引入某几个模块而不会因为需要一个小的功能就被强迫引入整个Spring框架。所以尽管Spring Framework包含的模块很多已经有二十几个但每个模块都非常轻量级都可以单独拿来使用。正因如此到现在Spring框架仍然可以被称为是一个轻量级的开发框架。
### 4.再封装、再抽象
Spring不仅仅提供了各种Java项目开发的常用功能模块而且还对市面上主流的中间件、系统的访问类库做了进一步的封装和抽象提供了更高层次、更统一的访问接口。
比如Spring提供了spring-data-redis模块对Redis Java开发类库比如Jedis、Lettuce做了进一步的封装适配Spring的访问方式让编程访问Redis更加简单。
还有我们下节课要讲的Spring Cache实际上也是一种再封装、再抽象。它定义了统一、抽象的Cache访问接口这些接口不依赖具体的Cache实现Redis、Guava Cache、Caffeine等。在项目中我们基于Spring提供的抽象统一的接口来访问Cache。这样我们就能在不修改代码的情况下实现不同Cache之间的切换。
除此之外还记得我们之前在模板模式中讲过的JdbcTemplate吗实际上它也是对JDBC的进一步封装和抽象为的是进一步简化数据库编程。不仅如此Spring对JDBC异常也做了进一步的封装。封装的数据库异常继承自DataAccessException运行时异常。这类异常在开发中无需强制捕获从而减少了不必要的异常捕获和处理。除此之外Spring封装的数据库异常还屏蔽了不同数据库异常的细节比如不同的数据库对同一报错定义了不同的错误码让异常的处理更加简单。
## 重点回顾
好了,今天的内容到此就讲完了。我们一块来总结回顾一下,你需要重点掌握的内容。
借助Spring框架我们总结了框架的作用解耦业务和非业务开发、让程序员聚焦在业务开发上隐藏复杂实现细节、降低开发难度、减少代码bug实现代码复用、节省开发时间规范化标准化项目开发、降低学习和维护成本等。实际上如果要用一句话来总结一下的话那就是简化开发
除此之外我们还重点讲解了Sping背后蕴含的一些经典设计思想主要有约定优于配置低侵入、松耦合模块化、轻量级再封装、再抽象。这些设计思想都比较通用我们可以借鉴到其他框架的开发中。
## 课堂讨论
1. “约定优于配置”在很多开发场景中都有体现比如Maven、Gradle构建工具它们约定了一套默认的项目目录结构除此之外你还能想到体现这条设计思想的其他哪些开发场景吗
1. 参照Spring的设计思想分析一个你熟悉框架、类库、功能组件背后的设计思想。
欢迎留言和我分享你的想法,如果有收获,也欢迎你把这篇文章分享给你的朋友。