写点什么

Spring Web 应用的最大瑕疵

  • 2013-11-08
  • 本文字数:2065 字

    阅读完需:约 7 分钟

众所周知, 现在的 Spring 框架已经成为构建企业级 Java 应用事实上的标准了,众多的企业项目都构建在 Spring 项目及其子项目之上,特别是 Java Web 项目,很多都使用了 Spring 并且遵循着 Web、Service、Dao 这样的分层原则,下层向上层提供服务;不过 Petri Kainulainen 在其博客中却指出了众多 Spring Web 应用的最大瑕疵,请继续阅读看看文中所提到的问题是否也出现在你的项目当中。

使用 Spring 框架构建应用的开发者很乐于谈论依赖注入的好处。但遗憾的是,他们很多人并没有在其应用中很好地利用其优势,如单一职责原则关注分离原则。如果仔细看看基于 Spring 的 Web 应用,你会发现很多都是使用如下这些常见且错误的设计原则来实现的:

  • 领域模型对象只是用来存储应用的数据。换句话说,领域模型使用了贫血模型这种反模式。
  • 业务逻辑位于服务层中,管理域对象的数据。
  • 在服务层中,应用的每个实体对应一个服务类。

可问题是:如果这种做法很普遍,那为什么说是不对的呢?下面来阐述一下。

旧习难改

Spring Web 应用之所以看起来是这个样子原因在于这是人们长久以来的做法,旧习难改,特别是在高级开发者或是软件架构师强制开发人员这样做的时候。问题在于这些人非常擅于捍卫自己的观点。他们喜欢的一个论调就是应用应该遵循关注分离原则,因为它被划分成了几个层次,每个层次都有自己具体的职责。

一个典型的 Spring Web 应用会有如下几个层次:

  • Web 层:负责处理用户的输入并向用户返回正确的响应。Web 层只会与服务层通信。
  • 服务层:作为事务边界。它还负责授权并包含了应用的业务逻辑。服务层管理着领域对象模型并且与其他服务及存储层通信。
  • 存储 / 数据访问层:负责与所用的数据存储进行通信。

关注分离原则的定义是这样的:关注分离(Soc)是一种将计算机程序划分到不同部分的一种设计原则,这样每一部分都会有单独的关注点。虽然一个典型的 Spring Web 应用也在一定程度上遵循了这个原则,不过实际情况却是应用拥有一个整体的服务层,它包含了太多的职责了。更具体一些,服务层主要有两个问题:

首先,应用的业务逻辑来自于服务层。

这是个问题,因为业务逻辑散落在服务层。如果需要查看某个业务规则是如何实现的,我们需要先找到它才行,这可不是那么轻松的事情。此外,如果有多个服务类都需要相同的业务规则,那么开发人员很可能会将这个业务规则从一个服务复制到另一个服务中,这会导致维护的梦魇。

其次,每个领域模型类在服务层中都有一个服务类。

这违背了单一职责原则:单一职责原则表明每个类都应该只有一个职责,这个职责应该完全被这个类所封装。它的所有服务都应该与这个职责保持一致。

服务类存在大量的依赖和大量的循环依赖。一个典型的 Spring Web 应用的服务层没有包含只拥有一个职责的松耦合的服务,它更像是一个紧耦合的大量服务的集合。这使得它很难理解、维护与重用。看起来有点苛刻,不过服务层经常是 Spring Web 应用最容易出现问题的一环。幸好对我们来说还存在着希望。

推翻

目前的状况并不好,不过也不是完全没有希望的。下面我们来看看如何打破旧有的习惯。

首先,我们需要将应用的业务逻辑从服务层移动到领域模型类中。

为何要这么做呢,看看下面这个例子:

假设我是个服务类,你是个领域模型对象。如果我告诉你从房顶跳下来,那么你是否会拒绝呢?

将服务层的业务逻辑移动到领域模型类中有如下 3 个好处:

  • 根据合理的方式划分代码的职责。服务层会负责应用的逻辑,而领域模型类则负责业务逻辑。
  • 应用的业务逻辑只会位于一处。如果需要验证特定的业务规则是如何实现的,我们总是知道该去哪里寻找。
  • 服务层的源代码将会变得更加整洁,再不会包含任何复制粘贴的代码了。

其次,我们需要将特定于实体的服务划分为更小的服务,每个服务只有一个目标。

比如说,如果应用有一个服务类,它为与用户帐户相关的人与操作提供了 CRUD 操作,那么我们就应该将其划分到两个单独的服务类中:

  • 第 1 个服务提供人的 CRUD 操作。
  • 第 2 个服务提供与用户帐户相关的操作。

这么做有如下 3 个好处:

  • 每个服务类都有一套合理的职责。
  • 每个服务类的依赖会更少,这意味着他们不再是紧耦合的庞然大物了。他们是更加小巧且松耦合的组件。
  • 服务类更易于理解、维护与重用。

这两个简单的步骤可以帮助我们清理应用的架构,提升开发者的生产力和幸福度。现在,我们想知道如果所有这些都是必要的,那么该何时解决这些问题呢?

有时生命是黑白的

我经常听到有人说我们不应该过多的关注于“架构”,因为我们的应用很小并且很简单。虽然这个论调有一定的正确性,不过我们必须要记住一开始很小的项目最后会变得很大。如果不考虑这种情况,那么一旦发生状况,我们就会陷入到巨大的麻烦当中。在未知的水域中航行可不是个好做法,但我们必须要知道,泰坦尼克号在撞到冰山沉没时是在熟悉的航线中航行的。这种事情也会发生在我们的应用中。当事情变得无法控制时,我们必须要有勇气说不。

如果你打算改变,那么我推荐你阅读一下Olivier Gierke 所写的“ Whoops! Where did my architecture ”(或是观看他在 SpringOne2GX 上关于这个项目的演讲)。但请注意,习惯的力量还是很强大的。

2013-11-08 11:329824
用户头像

发布了 88 篇内容, 共 272.3 次阅读, 收获喜欢 9 次。

关注

评论

发布
暂无评论
发现更多内容

产品经理训练营第三周作业

happy-黑皮

产品经理训练营

「产品经理训练营」作业 03

🌟

产品经理 产品经理训练营 产品经理训练

即兴演讲的几种实用脚本

熊斌

读书笔记 28天写作

手机里什么APP都没有,一个很无趣的人 | 视频号28天(27)

赵新龙

28天写作

超好用的文件转换神器!拿走不谢~

白色蜗牛

程序员 软件工具 生产工具

产品训练营·第三周作业 & 总结

tiu

浅谈OKR工作法

一笑

管理 OKR 28天写作

第 3 周作业

老元宵

28天瞎写的第二百三十六天:emacs 党的没落

树上

28天写作

offline app

lidaobing

28天写作 offline app

数据中心网络技术新贵:VXLAN与园区网络虚拟化

华为云开发者联盟

网络 数据中心 虚拟化 VXLAN 二层网络

浏览器同源策略,听说过么?

华为云开发者联盟

浏览器 jsonp CORS 同源策略 跨域

利益相关者的问题及方案

梁媛

深入理解 ProtoBuf 原理与工程实践(概述)

vivo互联网技术

数据结构 序列化 protobuf

产品经理训练营-第三周作业

玖玖

开发质量提升系列:日常重视好投产,运维拍肩也不怕

罗小龙

最佳实践 方法论 28天写作 2月春节不断更

熬夜肝了个IDEA插件整合程序员常用的工具,总有你能用上的

Silently9527

程序员 IDEA idea插件

工业互联网的“第一高地”,在哪?

工业互联网

GitHub 标星 167k!你要的优质书籍这都有,还开源!

沉默王二

GitHub 开源 电子书

从JNOS商业操作系统,看京东零售商业化之路新探索

京东科技开发者

零售 数字化转型

漫话递归与迭代

Justin

算法 方法论 成长 心灵鸡汤 28天写作

03- 抽奖小助手的那个「谁」

学习高手song轻松

产品训练营-第三次作业

Geek_娴子

为您收录的操作系统系列-进程管理(上篇)

鲁米

操作系统 进程

车载操作系统 (28天写作 Day26/28)

mtfelix

28天写作 车载操作系统 AOS QNX

如果创意也可以被设计「幻想短篇 26/28」

道伟

28天写作

考前复习必备MySQL数据库(关系型数据库管理系统)

我是哪吒

MySQL 程序员 面试 后端 2月春节不断更

【作业-03】解决方案的设计与积累

西西里奇

机器学习笔记之:最熟悉的陌生阵

Nydia

VUCA时代-不敏捷就得死

Ian哥

28天写作

【CSS】css控制鼠标点击事件(pointer-events)

德育处主任

html/css CSS小技巧 28天写作 纯CSS 2月春节不断更

Spring Web应用的最大瑕疵_架构_张龙_InfoQ精选文章