Spring 中的注解与分层思想

在Spring框架中最常见的几个注解

@Controller, @Service, @Component, @Repository

其中@Component是一种通用名称,泛指任意可以通过Spring来管理的组件,@Controller, @Service, @Repository则是一种特定的组件,通常用来表示某种特定场合下的组件,比如@Repository用来表示仓库(数据层,DAO),并且Spring 框架会根据这种应用场景做些定制,比如@Repository同时具备了自动化的异常转换。类似的, @Service则用来表示服务层相关的类, @Controller则用来表示展示层(presentation)的类。

那Service是什么呢?

Service 表示了在软件分层设计中的Service层,用来连结数据层(DAO)和展示层(Presentation)。

为什么要在DAO层上加一层Service呢?

对Java技术,架构技术感兴趣的同学,欢迎加QQ群:863621962,一起学习,相互讨论。

在某些简单的应用中,DAO层的功能和Service的功能很接近,甚至初学者会觉得Service层做的事情和DAO层都一样,那为啥还要将Service层单独拿出来做一遍呢?而且,很多场景下,Service层和DAO层同时存在,往往会增加代码复杂度,编码工作量,写的不好甚至会造成混淆。

通常来说,DAO层应尽力保持简单,其功能仅仅是提供了数据库的连接,以及最简单的增删改查(Crud),有时还需要做些抽象,以此来连接使用不同技术的数据库。除此之外,任何业务相关的操作都应该放到Service层,即Service层用来编写业务逻辑,即操作从DAO层读取的数据,或者将处理好的数据给DAO层,当使用Domain Driven Design时, 这两个类通常会放到同一个Domain(包)中,即便在简单的应用中,他们的代码可能极其类似,但是仍应该分别对待。而不是跳过service层(service)直接去使用DAO层(repository)来放业务逻辑数据。

这样带来的好处带来更好的模块化结构,有便于后期的扩展和维护,比如更换数据库实现时,我们仅仅需要处理DAO层的内容就好了。并且,当业务逻辑比较复杂的时候,比如有很多报告要出的时候,Service层就提供了一个很好的空间来实现这些代码。

其次,在web应用开发中,使用Service层可以将web类的活动限制在controller中,这样可以独立的测试service层

另外,还有一种情况,就是当应用极其复杂,需要同时使用多种数据库时,将从DAO中获取数据的动作放到一起可以减少数据库的操作,并且可以保证数据的一致性。同时Service可以嵌套,因此如果需要使用不同的数据库时,可以在service中指定。

在Service中也可以放一些通知类的操作,比如发送邮件等,这样也可以保持controller的整洁。

还有一个潜在的好处是安全性,当使用service层包裹DAO层后,数据库的链接是被service层保护起来的,这样如果客户端被某种情况攻陷,其只能使用service层提供的有限数据,而无法直接攻击数据库

另外,在Spring 框架中,security也是在Service层实现的。根据上面的逻辑,我们在实际开发中,应该不去实现自己的DAO层,而是使用Spring Data JPA,因为Spring Data JPA已经实现了DAO层。

这种写法常见的问题有啥?

最常见的写法(或者是错误的写法)有以下几种

1、面向领域的模型对象仅仅用来存储应用中的数据,换句话说,是不太符合domain model 设计的

2、处理模型数据的业务逻辑分散在service层

3、每个entity都有对应的service类

对Java技术,架构技术感兴趣的同学,欢迎加QQ群:863621962,一起学习,相互讨论。

这样写的原因很大程度来源于上面的分层理论,我们确实将应用分成了展示层(web layer),服务层(service layer),数据层(repository/dao),但是实际后果却是一个极其庞大的service层,这种写法可以算是一个面向过程开发的代码(procedural code), 而不是面向对象开发。好处是简单,当业务不复杂时,确实没有必要使用一个庞大的面向对象开发框架(domain driven design)。

一个责任并不明确的service层主要有以下问题

1、业务逻辑分散在service层中,当我们需要确认或者检查某个业务逻辑时,可能要在多个service类中寻找,也许并不那么容易,另外如果同样的业务逻辑在多个service类中用到时,那么可能会存在大量的重复代码,这种重复代码对于维护人员来说就是恶魔。

2、在service层中,每个entity都有对应的service类时,service层会有过多的依赖,甚至是循环依赖关系,而不是由松散耦合的service类构成service层,理想中的service层应该是由具有单一责任的service类构成,并且这些service类具有松耦合关系,如果不是这样的service层,将难以理解,维护和重用。

主要的解决方法是

1、将与entity相关的业务逻辑统一放到领域模型对象相关的类中,即所谓的domain service中。这样做的好处时,传统概念中的service层仅仅处理应用相关的业务逻辑,即作为Application Service。 然后domain service中处理domain 内的业务逻辑。业务逻辑将按照domain和application的方式分开,容易定位和维护。传统意义上的applicationservice层将变得整洁。

2、在domain service中我们将按照entity来编写对应的service,这些都是特定的service,很小,仅仅面对很专一的功能。举例来说,如果应用中的某个service提供person类的crud, 同时还提供用户帐号的操作,那么我们应该将person的crud单独放到一个service中,然后将用户帐号相关的操作放到另一个service中。

所有这些分层方式都是为了解决应用从小项目成长为大项目时可能遇到的隐患,代价是在项目还小时,增加了项目的复杂度,往往一句代码就能搞定的事情,却要拆到三个类中去。但是太多的实际例子表明,如果没有好的架构,当小项目膨胀到一定程度时,往往是无法维护的,只能全部推倒重写。

在Domain Driven Design中如何区分各种Service?

在DDD中,service有三种类型

Domain Service

Domain Service: 用于放置领域对象相关的业务逻辑,这些业务逻辑通常并不适合放到entity中,也不是常见到的CRUD(这些应该放到Repository), 将Domain Service 和Domain Objects放到一起是合理的,它们都是关注于domain相关的业务逻辑。在Domain Service中可以使用注入repository的方式来使用entity对应的repository。

举一个例子:

一个图书馆有三个entity:Book, Client,Inventory, 当把一本书借给一个客户时,就对应了一个Domain Service。在一个例子,在Eric Evans的《Domain Driven Design》书中,转账服务(FundsTransferService)也是一种domain service,它涉及到帐号BankAccount,但是并不适合放到BankAccount中。

Application Service

Application Service: 用于为应用外的client或consumer提供应用级别的服务,比如一个外部客户端(程序)需要使用某个entity的CRUD时,这些服务程序放到Application Service。

Application Service通常会使用Domain Service和repository来处理外部的请求。常见的场景是,从repository中拿到一些domain objects, 然后执行某些操作,在将其放回repository(或者不放), Application Service对应着大部分用户使用场景,在写一个应用时,可以先从Application service写起,这样可以很好界定应用的功能和范围。repository虽然可以在某些场景下注入到domain service中,但是更常见的是注入到applicatinoservice中。

Infrastructure service

还有一种Infrastructure service:用于抽象一些技术问题,比如消息队列,邮件服务

具体例子spring-petclinic

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏用户3254834的专栏

要钱有错吗?!

网络课堂的兴起,音频视频的商业化展示,当“白看”的电子书收取费用,当平民化的问答找不到答案,那些深耕领域作业的从业者执笔论经验、支桌开讲堂,富有阶层性的知识获取...

7610
来自专栏windealli

后台必备意识——柔性可用

柔性可用是指:当条件有限而不能向用户提供完美服务时,可以以柔性的方式提供有损的服务。

1.1K40
来自专栏奇点大数据

话说量化(4)

货币——也就是我们俗称的“钱”是世界上最可爱的东西之一,可以说没有它的刺激,也就没有我们现在这么繁荣的市场,也没有这么丰富的各类物质产品和幸福生活。

13120
来自专栏令仔很忙

这一年----On The Way

其实每次写总结,首先都要感叹一把,时间过的真的是太快了,当我们处于青春期的时候,总觉得时间过的好慢,什么时候能快点,早点上学,早点上高中,早点上大学,早点工作...

13020
来自专栏奇点大数据

话说量化(1)

从今天开始,我来写一个叫做《话说量化》的随笔。主要是最近自己业余也在玩量化交易的模型,那就把一路玩的过程中的感想和碰到的问题记下来,和一起玩的朋友们做个分享。既...

13620
来自专栏奇点大数据

话说量化(2)

市场,是一个很古老的概念了,至少已经有三四千年以上的历史了。较早的关于市场的记录是在古埃及时期,公元前两千多年之前,就已经有“Bazar”这个概念了,汉语里面也...

12620
来自专栏奇点大数据

话说量化(5)

钱是越多越好吗?这个问题似乎不用回答,那是肯定的啊。试问在座的各位看客哪位不是在挣钱,挣更多的钱,挣更多更多的钱的路上奔跑着的呢?钱是一种交换物质(当然也可以是...

10910
来自专栏葡萄城控件技术团队

生产制造MES系统中,如何应用报表分析?

中国制造业产业结构逐步从低附加值传统加工制造业和资源密集型制造业向高附加值新型制造业转型升级。生产制造类企业为了监控项目进度和产品生产情况,会需要制作大量的报表...

34530
来自专栏令仔很忙

知识扩展----快速阅读

而快速阅读就是充分利用左右脑,协调快速处理视觉信息。快速阅读也叫“全脑速读”。

9910
来自专栏编程坑太多

作为程序员,有没有让你感到既无语又崩溃的程序命名?

13930

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励