什么时候应该使用 RequestFactory 与 GWT-RPC?

Posted

技术标签:

【中文标题】什么时候应该使用 RequestFactory 与 GWT-RPC?【英文标题】:When should I use RequestFactory vs GWT-RPC? 【发布时间】:2011-05-06 09:55:30 【问题描述】:

我正在考虑是否应该将我的 gwt-rpc 调用迁移到新的 GWT2.1 RequestFactory cals。

Google 文档含糊地提到 RequestFactory 是一种更好的“面向数据的服务”的客户端-服务器通信方法

我可以从文档中提炼出一个新的 Proxy 类来简化通信(您不必来回传递实际实体,而只是传递代理,因此重量更轻且更易于管理)

这是重点还是我在大局中遗漏了什么?

【问题讨论】:

耶,这个问题链接自official gwt devguide! 【参考方案1】:

GWT RPC 和 RequestFactory 的最大区别在于 RPC 系统是“RPC-by-concrete-type”,而 RequestFactory 是“RPC-by-interface”。

RPC 上手更方便,因为您编写的代码行数更少,并且在客户端和服务器上使用相同的类。您可能会创建一个 Person 类,其中包含一堆 getter 和 setter,也许还有一些简单的业务逻辑,用于进一步切片和切分 Person 对象中的数据。这非常有效,直到您最终想要在您的类中包含特定于服务器的、非 GWT 兼容的代码。由于 RPC 系统基于在客户端和服务器上具有相同的具体类型,因此您可能会根据 GWT 客户端的功能遇到复杂性。

为了避免使用不兼容的代码,许多用户最终创建了一个对等点 PersonDTO,它隐藏了服务器上使用的真实 Person 对象。 PersonDTO 只是服务器端“域”、Person 对象的 getter 和 setter 的子集。现在您必须编写代码,在 PersonPersonDTO 对象以及您想要传递给客户端的所有其他对象类型之间编组数据。

RequestFactory 首先假设您的域对象不会与 GWT 兼容。您只需在 Proxy 接口中声明应该由客户端代码读取和写入的属性,RequestFactory 服务器组件负责封送数据并调用您的服务方法。对于具有明确定义的“实体”或“具有标识和版本的对象”概念的应用程序,EntityProxy 类型用于将数据的持久标识语义公开给客户端代码。使用ValueProxy 类型映射简单对象。

使用 RequestFactory,您需要支付前期启动成本来适应比 GWT RPC 轻松支持的更复杂的系统。 RequestFactory 的 ServiceLayer 通过添加 ServiceLayerDecorator 实例提供了更多的钩子来自定义其行为。

【讨论】:

这是支持我决定切换到 RequestFactory 的一个很好的理由。谢谢你,鲍勃!这是有道理的,我不明白为什么有些人说“在某些情况下使用 RPC,而在其他情况下使用 RF,这取决于您的需要”,因为使用 RPC 似乎您必须编写大量胶水代码和 DTO 层 RequestFactory 的另一个优点是它可以使用完全相同的代码与 android 和 GWT 一起使用。【参考方案2】:

我经历了从 RPC 到 RF 的过渡。首先我不得不说我的经验是有限的,我使用的 EntityProxies 和 0 一样多。

GWT RPC 的优点:

设置、理解和学习非常容易! 在客户端和服务器上使用相同的基于类的对象。 这种方法可以节省大量代码。 理想情况下,当在客户端和服务器上使用相同的模型对象(和 POJOS)时,POJO == MODEL OBJECTs == DTO 轻松将内容从服务器移动到客户端。 易于在客户端和服务器之间共享通用逻辑的实现(当您需要不同的逻辑时,这可能会成为一个严重的缺点)。

GWT RPC 的缺点:

不可能对服务器和客户端的某些方法有不同的实现,例如您可能需要在客户端和服务器上使用不同的日志记录框架,或者使用不同的 equals 方法。 无法进一步扩展的非常糟糕的实现:大多数服务器功能都是作为 RPC 类上的静态方法实现的。这真的很糟糕。 例如无法添加服务器端错误混淆 一些不能很好解决的安全 XSS 问题,请参阅文档(我不确定这对于 RequestFactory 是否更优雅)

RequestFactory的缺点:

真的很难从官方文档中理解,它的优点是什么!它从完全误导性的术语 PROXIES 开始——这些实际上是由 RF 自动创建的 RF 的 DTO。代理由接口定义,例如@ProxyFor(Journal.class)。 IDE 检查 Journal 上是否存在对应的方法。映射就这么多。 RF 在客户端和服务器的共性方面不会为您做太多,因为 在客户端上,您需要将“PROXIES”转换为您的客户端域对象,反之亦然。这完全是荒谬的。它可以在几行代码中以声明方式完成,但不支持!如果我们能更优雅地将我们的域对象映射到代理,那么像 javascript 方法 JSON.stringify(..,,) 之类的东西在 RF 工具箱中是缺失的。 不要忘记,您还负责将域对象的可转移属性设置为代理,等等。 服务器上的错误处理很差 - 默认情况下,服务器上会省略堆栈跟踪,并且您会在客户端上得到空的无用异常。即使我设置了自定义错误处理程序,我也无法访问低级堆栈跟踪!太糟糕了。 IDE 支持和其他地方的一些小错误。我提交了两个被接受的错误请求。不需要爱因斯坦来弄清楚这些实际上是错误。 文档很烂。正如我提到的,应该更好地解释代理,该术语具有误导性。对于我正在解决的基本常见问题,文档是无用的。 DOC 中另一个误解的例子是 JPA 注释与 RF 的连接。从简洁的文档中可以看出他们有点一起玩,是的,*** 上有一个相应的问题。我建议在理解 RF 之前忘记任何 JPA 的“连接”。

RequestFactory的优点

出色的论坛支持。 IDE 支持相当不错(但与 RPC 相比不是优势) 客户端和服务器实现的灵活性(松散耦合) 花哨的东西,连接到 EntityProxies,不仅仅是简单的 DTO - 缓存、部分更新,对移动设备非常有用。 您可以使用 ValueProxies 作为 DTO 的最简单替代品(但您必须自己完成所有不太花哨的转换)。 支持 Bean 验证 JSR-303。

总体上考虑 GWT 的其他缺点:

无法在提供 JUnit 支持的情况下运行集成测试(GWT 客户端代码 + 远程服务器)

不支持测试设置 - 无头浏览器 + 远程服务器

是的,可以运行 selenium 集成测试(但这不是我想要的)

JSNI 非常强大,但是在他们在会议上发表的那些闪亮的演讲中,他们并没有过多地谈论编写 JSNI 代码也有一些规则。同样,弄清楚如何编写简单的回调是值得真正的研究人员完成的任务。

综上所述,从 GWT RPC 到 RequestFactory 的过渡远非双赢局面, 当 RPC 最适合您的需求时。您最终会编写从客户端域对象到代理的大量转换,反之亦然。但是您的解决方案具有一定的灵活性和稳健性。论坛上的支持非常好,周六也是如此!

考虑到我刚才提到的所有优点和缺点,提前考虑这些方法中的任何一种是否真的可以改进您的解决方案和您的开发设置,而无需进行重大权衡,这是非常值得的。

【讨论】:

签出 JBoss Erai。我喜欢他们的 RPC 方法。【参考方案3】:

我发现为我的所有实体创建代理类的想法很烦人。我的 Hibernate/JPA pojos 是从数据库模型自动生成的。为什么我现在需要为 RPC 创建第二个镜像?我们有一个很好的“estivation”框架来处理“去休眠”pojo。

此外,定义服务接口的想法并不完全将服务器端服务实现为 java 契约,但确实实现了方法 - 对我来说听起来非常 J2EE 1.x/2.x。

【讨论】:

这很烦人,但是如果您无论如何都必须创建代理,那么您宁愿获得 RF 为您管理这些代理提供的额外帮助。不是每个人都想将整个 pojo 发送给客户端——例如,考虑一个扑克游戏——你的 Player 对象可能包含每个人都应该看到的信息(手牌数量、正面朝上的牌、总筹码)和其他信息一名玩家应该看到(面朝下的牌)。 您的扑克示例是有效的 - 我们通过使用我们的“estivation”框架用来抑制值的注释 (@WireTransient) 来解决这个问题。【参考方案4】:

与错误处理和测试能力较差的 RequestFactory 不同(因为它处理 GWT 底层的大部分内容),RPC 允许您使用更加面向服务的方法。 RequestFactory 实现了一种更现代的依赖注入风格的方法,如果您需要调用复杂的多态数据结构,它可以提供一种有用的方法。使用 RPC 时,您的数据结构需要更加扁平化,因为这将允许您的编组实用程序在您的 json/xml 和 java 模型之间进行转换。使用 RPC 还可以让您实现更健壮的架构,引用自 Google 网站上的 gwt dev 部分。

“简单的客户端/服务器部署

考虑服务定义的第一个也是最直接的方法是将它们视为应用程序的整个后端。从这个角度来看,客户端代码是您的“前端”,而在服务器上运行的所有服务代码都是“后端”。如果您采用这种方法,您的服务实现往往是更通用的 API,它们不会与特定应用程序紧密耦合。您的服务定义可能会通过 JDBC 或 Hibernate 甚至服务器文件系统中的文件直接访问数据库。对于许多应用程序来说,这种视图是合适的,而且它可以非常有效,因为它减少了层数。

多层部署

在更复杂的多层架构中,您的 GWT 服务定义可能只是轻量级网关,用于调用后端服务器环境,例如 J2EE 服务器。从这个角度来看,您的服务可以被视为应用程序用户界面的“服务器一半”。服务不是通用的,而是为您的用户界面的特定需求而创建的。您的服务成为“后端”类的“前端”,这些类是通过将对更通用后端服务层的调用拼接在一起编写的,例如,作为 J2EE 服务器集群实现。如果您需要后端服务在物理上与 HTTP 服务器分开的计算机上运行,​​则这种架构是合适的。”

另外请注意,设置单个 RequestFactory 服务需要创建大约 6 个 Java 类,而 RPC 只需要 3 个。更多代码 == 在我的书中有更多错误和复杂性。

RequestFactory 在请求处理期间也有更多的开销,因为它必须在数据代理和实际 Java 模型之间编组序列化。这个添加的接口增加了额外的处理周期,这在企业或生产环境中确实可以加起来。

我也不相信 RequestFactory 服务是像 RPC 服务一样的序列化。

总而言之,在使用了一段时间后,我总是选择 RPC,因为它更轻量级,更容易测试和调试,并且比使用 RequestFactory 更快。尽管 RequestFactory 可能比它的 RPC 对应部分更优雅和可扩展。增加的复杂性并不能使它成为一个更好的工具。

我认为最好的架构是使用两个 Web 应用程序,一个客户端和一个服务器。服务器是一个使用 servlet.jar 库的简单轻量级通用 java webapp。客户端是 GWT。您通过 GWT-RPC 向客户端 Web 应用程序的服务器端发出 RESTful 请求。客户端的服务器端只是通过 apache http 客户端,它使用持久隧道进入您在服务器 servlet Web 应用程序中作为单个 servlet 运行的请求处理程序。 servlet web 应用程序应该包含您的数据库应用程序层(hibernate、cayenne、sql 等)。这允许您将数据库对象模型与实际客户端完全分离,从而为开发和单元测试您的应用程序提供更可扩展和更健壮的方法。当然,它需要一点初始设置时间,但最终允许您创建一个位于 GWT 之外的动态请求工厂。这使您可以利用两全其美。更不用说无需编译或构建 gwt 客户端即可测试和更改服务器端。

【讨论】:

【参考方案5】:

我认为如果您在客户端有大量的 pojo,例如如果您使用 Hibernate 或 JPA 实体,这真的很有帮助。 我们采用了另一种解决方案,使用带有非常轻量实体的 Django 样式持久性框架。

【讨论】:

【参考方案6】:

我要提出的唯一警告是 RequestFactory 使用二进制数据传输(也许是 deRPC?),而不是普通的 GWT-RPC。

这仅在您使用 SyncProxy、Jmeter、Fiddler 或任何可以读取/评估 HTTP 请求/响应内容的类似工具(如 GWT-RPC)进行大量测试时才重要,但使用 deRPC 会更具挑战性或 RequestFactory。

【讨论】:

实际上 RequestFactory 确实提供了开箱即用的“纯 Java”实现,而不需要像 SyncProxy 这样的第三方工具。见***.com/questions/4853188/…【参考方案7】:

我们的项目中有一个非常大的 GWT-RPC 实现。 实际上,我们有 50 个 Service 接口,每个接口都有很多方法,而且编译器生成的 TypeSerializer 的大小会导致我们的 JS 代码变得庞大。 所以我们正在分析转向 RequestFactory。 我已经阅读了几天,深入研究网络并试图找到其他人在做什么。 我看到的最重要的缺点(也许我可能是错的)是使用 RequestFactory 您不再控制服务器域对象和客户端对象之间的通信。 我们需要的是以可控的方式应用加载/保存模式。我的意思是,例如,客户端接收属于特定事务的对象的整个对象图,进行更新,然后将整个对象发送回服务器。服务器将负责进行验证,将旧值与新值进行比较并进行持久化。如果来自不同站点的 2 个用户获得相同的事务并进行一些更新,则生成的事务不应该是合并的事务。在我的场景中,其中一个更新应该会失败。 我没有看到 RequestFactory 有助于支持这种处理。

问候 丹尼尔

【讨论】:

我也有这些担忧...您最终选择了 RF 吗?【参考方案8】:

公平地说,在考虑有限的 MIS 应用程序时,比如有 10-20 个可 CRUD 的业务对象,每个具有 ~1-10 个属性,这真的取决于个人喜好选择哪条路线吗?

如果是这样,那么也许预测您的应用程序将如何扩展可能是选择您的路由 GWT RPC 或 RequestFactory 的关键:

    预计我的应用程序将保留相对有限数量的实体,但它们的数量将大幅增加。 10-20 个对象 * 100,000 条记录。

    我的申请将在实体的广度上显着增加,但每个实体所涉及的相对数量将保持较低水平。 5000 个对象 * 100 条记录。

    预计我的应用程序将保留在相对有限数量的实体中,并且将保留在相对较少的实体中,例如10-20 个对象 * 100 条记录

就我而言,我正处于尝试做出此决定的起点。由于必须更改 UI 客户端架构以及做出传输选择,因此变得更加复杂。我之前的(显着)大规模 GWT UI 使用了 Hmvc4Gwt 库,该库已被 GWT MVP 设施取代。

【讨论】:

以上是关于什么时候应该使用 RequestFactory 与 GWT-RPC?的主要内容,如果未能解决你的问题,请参考以下文章

GWT 错误:必须运行 RequestFactory ValidationTool

如何在小工具中使用 GWT RequestFactory?

django测试RequestFactory不包含request.user

RequestFactory 请求 (AutoBeanCodexImpl.doCoderFor) 永远不会完成并使用 100% cpu

GWT 的各种异步设施

GWT RequestFactory + CellTable