设计模式学习笔记 - 开源实战四(上):剖析Spring框架中蕴含的经典设计原则

概述

在 Java 中,Spring 框架已经几乎成为项目开发的必备框架。作为如此优秀和受欢迎的开源项目,它是我们源码阅读的首选材料之一,不管是设计思想,还是代码实现,都有很多值得我们学习的地方。下面,就详细讲讲 Spring 框架中蕴含的设计思想、原则和模式。因为内存较多,会分成三部分来讲解。

  • 第一部分,讲解 Spring 框架中蕴含的经典设计思想或原则。
  • 第二部分,讲解 Spring 框架中用来支持扩展的两种设计模式。
  • 第三部分,总结罗列 Spring 框架中用到的其他十几种设计模式。

本章,先讲解第一部分:讲解 Spring 框架中蕴含的经典设计思想或原则,这其中就包括:约定大于配置、低侵入松耦合、模块化轻量级等。这些设计思想都很通用,掌握后,我们可以借鉴用到其他框架的开发中。


Spring 框架简单介绍

我们常说的 Spring 框架,是指 Spring Framework 基础框架。Spring Framework 是整个 Spring 生态的基石。除了 Spring Framework,Spring 全家桶中还有更多基于 Spring Framework 开发出来的、整合更多功能的框架,比如 Spring Boot、Spring Cloud。

在 Spring 全家桶中,Spring Framework 是最基础、最底层的部分。它提供了最基础、最核心的 IOC 和 AOP 功能。当然,它包含的功能还不仅如此,还有其他比如事务管理(Transactions)、MVC 框架(Spring MVC)等很多功能。下面这个表格,是从 Spring 官网上找的,关于 Spring Framework 的功能介绍。

模块说明
CoreIoc Container,Events,Resources,i18n,Validation,Data Binding,Type Conversion,SpEL,AOP
TestMock Objects,TestContext Framework,Spring MVC Test,WebTestClient
Data AccessTransactions,DAO Support,JDBC,O/R Mapping,XML Marshalling
Web ServletSpring MVC,WebSocket,SocketJS,STOMP Message
Web ReactiveSpring WebFlux,WebClient,WebSocket
IntegrationRemoting,JMS,JCA,JMX,Email,Tasks,Scheduling,Caching
LanguagesKotlin,Groovy,Dynamic Languages

在 Spring Framework 中,Spring MVC 出镜率很高,经常被单独拎出来使用。它是支持 Web 开发的 MVC 框架,提供了 URL 路由、Session 管理、模版引擎等跟 Web 开发相关的一些列功能。

Spring Boot 是基于 Spring Framework 开发的。它更加专注于微服务开发。之所以名字里带有 “Boot” 一词,跟它的设计初衷有关。Spring Boot 的设计初衷是快速启动一个项目,利用它可以快速地实现一个项目的开发、部署和运行。Spring Boot 支持的所有功能都是围绕着这个设计初衷的,比如:集成很多的第三方开发包、简化配置(比如,规约优先于配置)、集成内嵌 Web 容器(比如 Tomcat、Jetty)等。

单个的微服务开发,使用 SpringBoot 就足够了,但是如果要构建整个微服务集群,就需要用到 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)。通过约定的代码结构或者命名来减少配置。说直白点,就是提供配置的默认值,优先使用默认值。程序员只需要配置那些偏离约定的配置就可以了

基于刚刚的约定,代码中定义的 Order 类就对应数据库中 “order” 表。只有在偏离这一约定时,例如数据库中表命名为 :“order_info” 而 “order”,我们才需要显示地去配置类与表的映射关系(Order 类 -> order_info 表)。

实际上,约定优于配置,很好地体现了 “二八法则”。在平时的项目开发中,80% 的配置使用默认值,只有 20% 的配置必须用户显示地去设置。所以,基于约定来配置,在没有牺牲配置灵活性的前提下,节省了我们大量编写配置的时间,省掉了很多不动脑子的纯体力劳动,提高了开发效率。此外,基于相同的约定来做开发,也减少了项目的学习成本和维护成本

2.低侵入、松耦合

框架的侵入性是衡量框架好坏的重要指标。所谓低侵入指的是,框架代码很少耦合在业务代码中。低侵入意味着,当我们要替换掉一个框架时,对原有的业务代码改动会很少。相反,如果一个框架是高侵入的,代码高度侵入到业务代码中,那替换成另一个框架的成本会非常高,甚至几乎不可能。这也是长期维护的老项目,使用的框架、技术比较老旧,又无法更新的一个很重要的原因。

实际上,低侵入是 Spring 框架遵循的一个非常重要的设计思想。

Spring 提供的 IOC 容器,在不需要 Bean 继承任何父类或者实现任何接口的情况下,仅仅通过配置,就能将它们纳入 Spring 的管理中。如果我们换一个 IOC 容器,也只是重新配置一下就可以了,原有的 Bean 都不需要任何修改。

此外,Spring 提供的 AOP 功能,也体现了低侵入的特性。在项目中,对于非业务功能,比如请求日志、数据采点、安全校验、事务等等,我们没必要将它们侵入进业务代码中。因为一旦侵入,这些代码将分散在各个业务代码中,删除、修改的成本就变得很高。而基于 AOP 这种开发模式,将非业务代码集中放到切面中,删除、修改的成本就变得很低了。

3.模块化、轻量级

十几年前 EJB 是 Java 企业级应用的主流开发框架。但是,它非常臃肿、复杂,侵入性、耦合性高,开发、维护和学习的成本都不低。所以,为了替代笨重的 EJB,Rod Johnson 开发了一套开源的 Interface21 框架,提供了最基本的 IOC 功能。实际上,Interface21 框架就是 Spring 框架的前身。

但是,随着不断发展,Spring 现在也不单单只是一个包含 IOC 功能的小框架了,它显然已经壮大成了一个 “平台” 或者叫 “生态”,包含各种五花八门的功能。尽管如此,但它并没有重蹈覆辙,变成一个像 EJB 那样的庞大难用的框架。那 Spring 是怎么做到的呢?

这就要归功于 Spring 的模块化设计思想。如下图所示,它是 Spring Framework 的模块和分层介绍。
在这里插入图片描述
从图中可以看出,Spring 在分成、模块化方面做得非常好。每个模块都只负责一个相对独立的功能。模块之间的关系,仅有上层对下层的依赖关系,而同层之间以及下层对上层,几乎没有依赖和耦合。此外,在依赖 Spring 的项目中,开发者可以有选择地引入某几个模块,而不会因为需要一个小的功能,就被强迫引入整个 Spring 框架。所以,经 Spring Framework 包含的模块很多,但是每个模块都非常的轻量级,都可以单独拿来使用。正因为如此,到现在,Spring 框架爱仍然可以被称为是一个轻量级的框架。

4.再封装、再抽象

Spring 不仅仅提供了各种 Java 项目开发的常用功能模块,而且还对市面上主流的中间件、系统的访问类库,做了进一步的封装和抽象,提供了更高层次、更统一的访问接口

比如,Spring 提供了 spring-data-redis 模块,对 Redis Java 开发类库(比如 Jedis、Lettuce)做了进一步的封装,提供了更高层次、更统一的访问接口。

还有,在后面章节要讲解的 Spring Cache,实际上也是一种再封装、再抽象。它定义了统一、抽象的 Cache 访问接口,这些接口不依赖具体的 Cache 实现(Redis、Guava Cache、Caffeine 等)。在项目中,我们基于 Spring 提供的抽象统一的接口来访问 Cache。这样,我们就能在不修改代码的情况下,实现不同 Cache 之间的切换。

此外,还记得我们之前在模板模式中,讲过的 JdbcTemplate 吗?实际上,它也是对 JDBC 的进一步封装和抽象,为的是进一步简化数据库编程。不仅如此,Spring 对 JDBC 异常也做了进一步的封装。封装的数据库异常继承自 DataAccessException 运行时异常。这类异常在开发中无需强制捕获,从而减少了不必要的捕获和处理。此外,Spring 封装的数据库异常,还屏蔽了不同数据库异常的细节(比如,不同的数据库对同一报错的定义了不同的错误码),让异常的处理更加简单。

总结

借助,Spring 框架,我们总结了框架的作用:

  • 解耦业务和非业务开发、让程序员聚焦在业务开发上;
  • 隐藏复杂实现细节、降低开发难度、减少代码 bug;
  • 实现代码复用、节省开发时间;
  • 规范化标准化项目开发、降低学习和维护成本等。

用一句话总结,就是简化开发

此外,还重点讲解了 Spring 背后蕴含的一些设计思想,主要有:

  • 约定优于配置
  • 低侵入、松耦合
  • 模块化、轻量级
  • 再封装、再抽象

这些设计思想都比较通用,我们可以解决到其他框架的开发中。

  • 22
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值