初步认识架构分层

一般初创软件,为快速上线,几乎不考虑分层。但随业务越发复杂,就会导致逻辑复杂、模块相互依赖、代码扩展性差等各种问题。

架构分层迫在眉睫。

1 什么是架构分层?

软件工程中常见的设计方式,将整体系统拆分成N个层次,每个层次有独立的职责,多个层次协同提供完整的功能。

初学 JavaWeb 时一般要求设计成 MVC 架构。另外一种常见的分层方式是将整体架构分为

  • 表现层(Web) 展示数据结果和接受用户指令的,是最靠近用户的一层;
  • 逻辑层(Service) 复杂业务的具体实现;
  • 数据访问层(Dao) 主要处理和存储之间的交互。

这就可以隔离关注点,让不同的层专注做不同的事情。其它分层案例,比如OSI网络七层模型,TCP/IP协议网络四层模型。

2 分层有什么好处?

简化设计

各司专职,而不必将自己活成全才。

高复用

比如在设计某系统时,发现某层具有通用性,就可把它抽取独立出来,在设计其它系统时使用。

横向扩展

可以让我们更容易做横向扩展。如果系统没有分层,当流量增加时我们需要针对整体系统来做扩展。但是,如果我们按照上面提到的三层架构将系统分层后,就可以针对具体的问题来做细致的扩展。

比如业务逻辑里面包含有比较复杂的计算,导致CPU成为性能的瓶颈,那这样就可以把逻辑层单独抽取出来独立部署,然后只对逻辑层来做扩展,这相比于针对整体系统扩展所付出的代价就要小的多了。

架构分层究竟和高并发设计的关系是怎样的?我们知道横向扩展是高并发设计思想之一,既然架构分层可方便横向扩展, 那么高并发系统一定是分层的。

3 如何架构分层?

关键在于理清层次边界。 若按三层架构分层,边界不就很容易界定吗? 是的没毛病,当业务逻辑简单时,层次间边界的确清晰,开发新功能时也知道把代码往哪写。但当业务逻辑越来越复杂,边界也会变得模糊。

3.1 案例

任一系统都有用户模块,比如返回用户信息的接口,它调用逻辑层的GetUser方法,GetUser方法又和User DB交互获取数据,就像下图左边展示的样子。

这时,产品提出一个需求,在APP中展示用户信息的时候,若用户不存在,那么要自动给用户创建一个用户。同时,要做一个HTML5页面保留之前的逻辑,即不需要创建用户。这时逻辑层的边界就变得不清晰,表现层也承担了一部分的业务逻辑(将获取用户和创建用户接口关联)。

3.2 主流分层职责

MVC架构的简单性让太多的人觉得项目工程结构理所应当就是这样的,然后呢,一大堆的业务逻辑就随意的堆砌在了service中,对象啥的,只是单纯的数据传输作用,出现了用面向对象的语言,写面向过程的程序的普遍现象。按照领域驱动设计的思路,最重要的还要有领域模型层。当然manage层这种方案也是一种思路,但是我觉得,这种方式,还不够,必须有清晰的业务模型和合理的分层结构配合,才能更好的提现分层的作用。

终端显示层

各端模板渲染并执行显示的层。当前主要是 Velocity/framemaker渲染、js渲染、移动端展示等

开放接口层

将Service层方法封装成开放接口,同时进行网关安全控制和流量控制等

Web层

主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等

Service层

业务逻辑层。调用manager层和dao层处理业务,即简单的业务可以不抽取manager,直接调用dao。 业务类的校验放在service层,一般性的参数校验可以放在web层,这可以通用化。

Manager 层(通用业务处理层)

DDD中也叫领域层。

  1. 可以将原先Service层的一些通用能力下沉到这一层,比如与缓存和存储交互策略,中间件的接入。业务逻辑放在manager,service来编排manager的原子服务。
  2. 也可在这一层封装对第三方接口的调用,比如调用支付服务,调用审核服务等

该分层架构相比MVC主要就是增加了Manager层,它与Service层的关系:Manager层提供原子的服务接口,Service层负责依据业务逻辑来编排原子接口。

  • 业务逻辑就是你的产品逻辑,比如创建用户要具体做什么。
  • manager层的原子服务指的是实现单一功能的服务。
  • 事务应该在service层

DAO层(数据持久层)

数据访问层,与底层 MySQL、Oracle、HBase 等进行数据交互。缓存可以放在存储层。

外部接口或第三方平台

包括其它部门 RPC 开放接口,基础平台,其它公司的 HTTP 接口

例如,Manager层提供创建用户和获取用户信息的接口,Service层负责将这两个接口组装起来。这样就把原先散布在表现层的业务逻辑都统一至Service层,每层边界就清晰了。

比如做一个接口,可将实现放在service层。之后公司内部调用逻辑可放在web层。而哪一天公司要开放这个接口,可直接新抽象一层(一个新的服务),即开放平台层!这样的好处是,可以将本司使用和第三方使用做隔离。比如在提供服务时,为了保证自家接口性能,对开放平台层做限流处理。

传统公司很多是分层部署的,比如保险和金融。service和dao部署在比较严密的网络区域,controller层部署在一个较宽松的网络区域,对外提供服务。等于在网络上增加了一个缓冲区,来保证服务的安全;而且可以通过单向网络规范层级调用,controller可以调用服务层,而服务层是不能调用web层的。 如果将数据访问层单独部署,比如拆分为单独的rpc服务,当然这样拆分粒度比较细。controller就是对外的门面,调用单独的服务层

  • 可以为后期服务运维降低成本
  • 可以提高数据访问层的复用度(数据访问层对外提供API,其他层的应用通过API方式与数据库进行交互),三来可以屏蔽各个数据库实现的具体细节。

3.3 层间依赖

数据流转只能在相邻层间。以三层架构为例,数据从表示层进入后一定要流转到逻辑层,做业务逻辑处理,然后流转到数据访问层和DB交互。但若业务逻辑很简单,可否从表示层直接到数据访问层,甚至直接读DB? 功能上是可以的,但从长远架构设计考虑,这会造成层级调用混乱,比如一旦DB地址变更,就需更改多层,这就失去了分层价值,且维护或重构都是灾难。

4 架构分层的缺陷

4.1 增加代码复杂度

原本可在接收请求后直接查询DB获得结果,却非要在中间多层设计,每层只简单地做数据传递。 有时增加一个小需求,可能还需更改所有层的代码,增加了开发成本,也增加了调试复杂度,增加了与其它模块负责人的沟通成本。

4.2 性能损耗

若每层独立部署,层间通过网络交互,那多层架构势必会在性能上有所损耗。

那是否还要选择架构分层呢?肯定的。

你要知道,任何的方案架构都是有优势有缺陷的,天地尚且不全何况我们的架构呢?分层架构固然会增加系统复杂度,也可能会有性能的损耗,但是相比于它能带给我们的好处来说,这些都是可以接受的,或者可以通过其它的方案解决的。我们在做决策的时候切不可以偏概全,因噎废食。

5 总结

分层架构是软件设计思想的外在体现,是一种实现方式。一些软件设计原则都在分层架构中有所体现。

比方单一职责原则规定每个类只有单一的功能,在这里可引申为每层拥有单一职责,且层与层之间边界清晰; 迪米特法则原意是一个对象应当对其它对象尽可能少的了解,在分层架构的体现是数据的交互不能跨层,只能在相邻层之间进行;

开闭原则要求软件对扩展开放,对修改关闭。它的含义其实就是将抽象层和实现层分离,抽象层是对实现层共有特征的归纳总结,不可修改,但具体实现可无限扩展,随意替换。

参考

  • 《阿里巴巴Java开发手册》

本文由mdnice多平台发布

相关推荐
Java水解13 分钟前
Spring Boot 配置文件深度解析
spring boot·后端
狗头大军之江苏分军19 分钟前
Node.js 性能优化实践,但老板只关心是否能跑
前端·后端
李拾叁的摸鱼日常28 分钟前
Java泛型基本用法与PECS原则详解
java·后端·面试
狗头大军之江苏分军29 分钟前
Node.js 真香,但每次部署都想砸电脑
前端·javascript·后端
帅那个帅1 小时前
go的雪花算法代码分享
开发语言·后端·golang
酒酿萝卜皮1 小时前
Elastic Search 聚合查询
后端
程序员清风1 小时前
阿里二面:新生代垃圾回收为啥使用标记复制算法?
java·后端·面试
sino爱学习1 小时前
Java 三元表达式(?:)的常见坑总结
java·后端
❀͜͡傀儡师1 小时前
Spring Boot函数式编程:轻量级路由函数替代传统Controller
java·spring boot·后端