原文:JPA implementation patterns: Service Facades and Data Transfers Objects
作者:Vincent Partington
出处:http://blog.xebia.com/2009/05/11/jpa-implementation-patterns-service-facades-and-data-transfers-objects/
在前一篇关于JPA实施模式的博客中,我谈到了DTO和服务门面(Service Façade)模式这一主题,在本篇博客中,我将会探讨为什么我们需要这些模式,甚至会把它们和DAO模式应用到JPA应用架构的更广泛的情形中。
在首次实现JPA代码时,如果说我从中学到了一样东西的话,那就是一些“守旧派”企业应用的架构模式仍然适用,尽管有人已经宣布他们不再是必要的:
DAO已被宣布死亡,因为你只要直接调用EntityManager就可以了,它提供了一个足够好的接口,但从JPA到不同的持久性实现的转换不如使用DAO抽象来得容易。
DTO被认为是多余的,因为你也可以在表现层中直接使用领域对象,视图模式中的打开的EntityManager、显示JSP中的领域对象的标签库和把HTTP请求参数映射回领域对象的数据绑定实用程序的联合使用使这一做法变成可能,
而且最终看来服务门面似乎也已过时,作为替代,你可以让控制器直接调用其所需的服务,或者甚至更简单,直接在其内部包含业务逻辑。
由此产生的应用架构看起来就像是这一Spring的Web MVC应用架构图中显示的样子:
那么为什么要关注DAO、DTO和服务门面呢?
我曾经论证过为什么DAO模式在JPA应用架构中仍然是有价值的,类似的理由可以用在DTO和服务门面模式上。虽然前面显示的缺少DTO和缺少服务门面的架构对于简单的Web应用来说可以工作得很好,但是它有两个主要的缺点:
如果你希望把应用暴露给其他的非HMTL客户端(考虑一下使用SOAP的web service、使用AMF的Flex前端或者使用JSON的Ajax应用)的话,那么你会需要一个更明确界定的接口,该接口指定哪些服务被暴露给客户端以及哪些类型被用作输入和输出,服务门面和DTO会各自帮助你定义此接口。
直接在表示层使用领域对象要求这些领域对象使用getter和setter方法来把它们所有的域暴露成公共属性,如果域没有被如此暴露的话,那么标签库将无法呈现它们且数据绑定代码不能设定它们。正如Allen Holub之前已论证的那样,getter和setter方法是有害的。(顺便说一下,有些人把Holub的文章理解为把所有域修饰成公共的的借口,该文认为公共的getter和setter方法不太好,但那并不意味着代码中就只用公共的域,相反,文章建议使用告知而非询问(tell, don’t ask)的面向对象方法。)
实际上我发现为什么服务门面和DTO依然有用的原因是因为,我和我的团队正在开发的应用有一个Flex前端和一个与分别使用AMF和Hessian与核心通信的命令行界面,而应用产生的HTML代码只是为Flex前端加载SWF文件!我们开始的时候就像一般人的做法一样,并未用到DAO、DTO和服务门面,不过我们把它们全部添加到了我们的架构中以确保其成功,因此作为一个额外的奖赏,我们得到了一个在服务层和表现层之间明确定义的接口。
DTO的优缺点
当然如果说应该总是在架构中使用DTO那是愚蠢的,一如往常,要视情况而定。J为了让你做出自己的决定,我将列出使用DTO的一些优点和缺点:
缺点:DTO导致代码重复,特别是在DTO与领域对象有着完全相同的域的时候,在两者都为这些域配备了getter和setter方法的时候更是如此,不过在架构中使用DTO可以让你省去领域对象中的getter和setter方法。
缺点:DTO需要你编写来回拷贝属性的样板代码,有些人建议使用诸如Dozer、Apache Commons BeanUtils或者Spring框架的BeanUtils类一类的Java Bean映射框架,不过这需要你把getter和setter方法添加到你的bean中,而我们才刚刚决定我们不想再这样做了!
优点/缺点:DTO使得使用EntityManager.merge来把它们的内容拷贝到你的持久性对象中变为不可能,相反,你不得不使用在我的那篇关于保存(游离的)实体的博客中所描述的DIY合并模式(DIY merge pattern),当然,迫使你以特别的方式,并且不是百分之百令人满意的方式做一些事情,实在不是什么优点,不过至少DTO和DIY合并之间配合得很好。
优点:DTO确保你不会在表现层中遭遇意想不到的延迟加载问题,或者在远程调用的情况下,它们会使你避免在序列化客户端的传输甚至是未知情况时所产生的延迟加载问题。
优点:DTO模式迫使你考虑应用的接口,你可以把DTO变得比普通的领域对象更为丰富,例如,把安全信息添加到其中,或者把来自多个领域对象的信息聚集起来放到一个DTO中使接口更易于使用。
在我们继续讨论服务门面之前,也许应该看看Anirudh Vyas的这篇关于DTO模式的常见不当用法。
服务门面的优缺点
正与DTO的情况类似,在一些情况中服务门面非常有意义,而在一些情况中它们只是增加了无意义的开销,让我们来看看其中的一些优点和缺点:
缺点:服务门面增添了一个额外的层次,该层除了代表实际的服务外并没有做太多的事情,这一理由对于那些有着关于基于我们在本世纪初创立的多层架构的EJB1.0的不好回忆的Java EE开发者来说,是特别的有感触。
优点:服务门面可以(应该!)负责DTO和领域模型之间的来回映射,服务门面在被调用时以DTO为参数,把它们映射到领域模型,调用实际的某个服务(或多个服务),把结果映射回DTO并把这些DTO返回给客户端。实际上,为了确保服务门面只遵守单一责任原则(Single Responsibility Principle),你应该把映射逻辑提出来,放到单独的DTO2DOMapper和DO2DTOMapper类中。
优点:服务门面可起到应用的事务边界的作用,即事务在请求到达服务门面期间开始,而不再需要为所有服务定义事务属性,你可以假定所有的服务都通过服务门面来获得调用。实际上,在处理请求期间希望调用多个服务时,或者在想让服务门面把延迟加载的领域对象映射到DTO上的时候,把服务门面设置成事务的边界则是必须要做的事情,在这种情况下,你最终得到的是视图模式中的打开的EntityManager之类的对象;启动的事务从把进来的DTO转换成领域对象这一刻开始,一直持续到把最终产生的DTO返回给客户端这一刻为止。(顺便说一下,如果你希望强制通过服务门面来调用所有的服务的话,那么你可以把这些服务的事务属性设置为MANDATORY。当这样的一个服务被调用时,如果事务还没有被启动,就会有异常抛出。)
优点:服务门面会迫使你思考应用的接口,而不是允许客户端访问你所有的服务,你可以决定最终暴露哪些。
嘿,我好像还没有想到服务门面模式太多的缺点,除了“开销”这一说法之外,不过这是一种较主观的看法。请不要迟疑,随时在评论部分中添加更多的关于这一模式的缺点。
对应用架构的影响
如果应用DAO、DTO和服务门面模式的话,我们最终得到的JPA应用架构看起来会是这样子的:
当有请求产生时,事件是以这样的顺序发生的:
1. 服务的客户端发送请求到服务门面,发送的所有对象都是DTO。
2. 开始一个事务。
3. 服务门面调用DTO2DO映射器把进来的DTO映射到领域对象上,DTO2DO映射器可以调用一个或多个DAO来从数据库中加载领域对象。
4. 服务门面调用一个或多个服务来执行实际的业务逻辑。
5. 服务门面把返回值传递给DO2DTO映射器并得到返回的DTO,DO2DTO映射器可以调用一个或多个服务或DAO来给DTO添置内容。
6. 提交事务,或者在异常抛出的情况下回滚事务。
7. 服务门面把DTO传递给客户端。
8. 服务的客户端接收DTO。
实际上,如果把图中的“DTO2DO映射器”替换成“数据绑定”,把“DO2TDO映射器”替换成“视图呈现”,以及把“服务门面”替换成“前端控制器”的话,那么你就会得到我们一开始时提到的原始的Web MVC架构,其最大的不同在于进来的“DTO”是请求参数而出去的“DTO”是HTML:
这使得本篇博客回到了其开始的地方,所以现在是时候来个最后的总结了。正如你所见到的那样,在是否使用DTO和服务门面这个问题上,并没有什么明确的答案,这完全取决于你要实现的应用是什么样的,比如说:
它是一个普通的HTML应用还是你希望通过不同的协议来暴露它?
你希望客户端和服务端之间的耦合程度是怎样的?
你希望领域对象不带有任何的getter和setter方法吗?
我很有兴趣听一听关于这些模式在当前的Java EE架构中的有效性你们是怎么想的?在什么情况下会使用它们?或者哪些情况下不会使用它们以及为什么?我们在下篇博客中再见,下次我会尝试解决如何在JPA中处理继承这一问题。
附:上周我给info.nl的一帮家伙就这一主题做了一个介绍,他们给我提供了一些很有意思的反馈意见,对本篇博客的形成很有帮助,感谢他们!
- 大小: 12.7 KB
- 大小: 14.7 KB
- 大小: 14.4 KB
分享到:
相关推荐
一共有三个分卷。全部下载才能解压。 这本书不错,值得一看。
**JPA(Java Persistence API)**是Java平台上的一个标准,用于管理关系数据库中的数据,它简化了数据库操作,提供了一种面向对象的方式来处理数据库事务。JPA通过ORM(Object-Relational Mapping)映射机制将Java...
要在 Spring Boot 项目中集成 Spring Data JPA,首先需要在 pom.xml 文件中引入相关依赖包,包括 Spring Boot 的数据 JPA starter 依赖和 MySQL 的连接器依赖。 在 Application 入口程序类上方,可以添加一些注解来...
蓝图 JPA 图表 蓝图 API 在(1)。... 在使用EclipseLink和Hibernate的情况下,一次提交添加海量数据非常慢,那么我们应该将海量数据分成多个子块。 微基准仅作为指导 东方数据库 JPA:ObjectDB(*1) JPA:Ecl
在处理关联关系时,Spring Data JPA提供了懒加载和急加载(Eager vs Lazy Fetching)机制,通过配置实体类的属性映射,可以在需要时按需加载关联的数据,避免了N+1查询问题。同时,它还支持级联操作(Cascade ...
【标题】"notes_JPA_JSF:使用JSF和JPA实施来重建Notes项目"涉及的是在Java开发环境中,利用JavaServer Faces (JSF) 和 Java Persistence API (JPA) 技术重构建一个名为Notes的项目。JSF是Java EE平台上的一个用户...
在现代企业级应用开发...总的来说,Spring Boot结合JPA或MyBatis实现多数据源动态切换,不仅提高了系统的灵活性,还便于进行数据库扩展和管理。理解和掌握这一技术,对于提升系统设计能力和解决复杂问题具有重要意义。
JPA允许你在Java应用程序中以对象的形式处理数据,这些对象可以自动转换为数据库中的记录。 在JPA的例子中,我们通常会涉及以下几个核心概念: 1. **实体(Entity)**: 实体是与数据库表相对应的Java类。它们通常...
春天数据jpa额外使用jpa的spring数据更舒适我爱spring-data-jpa,她放开我的双手,粗鲁的方法很无聊! 然而,尽管她为我们提供了规范解决方案,但她在动态本机查询上并不完美,而且她的返回类型必须是一个实体,但是...
这对于那些需要确保实体对象数据是最新的场景非常有用。 5. **使用`clear()`方法** `clear()`方法会清除实体管理器当前上下文中所有的托管实体对象,使它们变为游离状态。需要注意的是,未及时提交到数据库的更改...
在`src`目录中,可能包含了项目的源代码,包括实体类、DAO层的实现、服务层逻辑等,通过分析这些源码,我们可以深入理解JPA在实际项目中的应用方式和最佳实践。 总结来说,JPA作为Java的持久化框架,简化了数据库...
vraptor4-jpa-hibernate”是一个项目名称,暗示了这个课程作业主要探讨了在Java环境中如何实现持久化,特别是在使用vraptor4框架、Java Persistence API (JPA) 和 Hibernate ORM工具时的数据存储技术。下面将详细...
本文是介绍Spring-data-jpa的PPT的学习笔记,整理了Spring Data JPA相关知识配置和实践源码. 本文介绍知识点有: JPA与Spring的相关配置 JPA 方法名常用查询 JPA 使用@Query注解实现JPQL和本地自定义查询 JPA API 条件...
使用SpringBoot-JPA进行自定义保存及批量保存功能是指在Spring Boot应用程序中使用JPA(Java Persistence API)来实现自定义的保存和批量保存功能。JPA是一个Java API,它提供了一种对象关系映射(ORM)机制,允许...
ORM 映射元数据:JPA 支持 XML 和 JDK 5.0 注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中。 JPA 的 API:用来操作实体对象,执行CRUD操作,框架在后台完成所有...
Spring Data Jpa常用功能演示配套说明请查看:项目简介本项目采用当前最新版本的2.1.4.RELEASE做基础架构支撑,请参考本项目建议有一定的基础及经验。教程主要针对中文用户,如果您英文良好,建议直接阅读官网帮助...