Web架构:MVC,懒惰初始化,数据传输对象,Open Session In View,是否有共识方法?

时间:2009-12-28 12:35:07

标签: hibernate spring architecture web-architecture

对于典型的Web 3层应用程序,您在以下设计中看到了哪些缺陷(以及您理想的体系结构建议)?

我目前的蓝图方法非常粗略(假设是Java,Spring,Hibernate,JSP)


控制器

无状态,可能包含只读事务(以避免延迟初始化异常),仅通过服务从持久性存储中获取实体,将它们作为模型传递给视图。对它们进行业务逻辑(如果BL只在服务层中?),如果需要,则传回服务层以实现持久性。

优点:对于只读事务包装 - 只有一个连接,同一个持久实体没有冗余命中,更好地利用查询缓存,服务层不应“知道”请求参数,或者需要init graph span,避免延迟初始化异常。

缺点:只读事务方法可能存在风险,控制器不是理想的业务逻辑挂起的地方......很难做到JUnits(您的输入是请求......)< / p>


查看

非事务性(访问非惰性集合/成员将导致惰性初始化异常)

优点

  • 视图作者不应仅仅通过点符号来影响应用程序的性能(例如,由于懒惰初始化大型集合而导致N + 1选择。

  • 此外,在断开连接的客户端(Flex或其他富客户端)中,远程延迟初始化是不受支持的,或者只是不聪明的事情

缺点:控制器/服务/ DAO必须仔细准备视图的实体的正确图形,并且可能是过冲(性能)/下冲(延迟初始化异常)。无数的服务器端方法可能会导致混乱,因为有一个笛卡尔乘积与排列的数量可以初始化实体图


模型

按原样使用持久对象(无数据传输对象),状态将保存在会话中。

优点:无需重写POJO,重用现有实体,会话状态比隐藏字段状态处理更安全。

缺点:对于断开连接的框架,保存过时的断开对象的风险,锁定问题的风险,覆盖其他数据的错误,有时需要乐观锁定。


服务

Transactional,不知道请求范围,调用DAO层进行实际持久存储访问。这是BL应该经典的地方,但似乎BL一遍又一遍地泄漏到控制器端。


DAO

包含原子持久性存储外观,不知道BL或任何上下文


最后,问题是:

您将在上述架构中解决什么问题?

你认为(像我一样)这是一种非常常见的方法(有一些细微差别,比如开放会话等)?或者这是你第一次看到它而我正在做一些非常错误(或正确)的事情?

您如何在应用程序中解决它?您是否也将您的实体POJO用于​​您的模型和视图?或者你把它连接到更简单的UI bean(所有完全初始化和安全)?

这可能是一个主观问题,但我确信有明确的最佳实践设计模式可以聚为一,二或三种最常见的“宗教”。

4 个答案:

答案 0 :(得分:3)

总的来说,它似乎是一个非常好的架构。如果您还没有阅读过,我会推荐Martin Fowlers企业应用程序架构模式,它描述了您问题中的每个主题。

从问题中您预计性能有多大这一问题尚不清楚。根据我的经验,性能瓶颈很少在您认为的位置,并且越早发现它们,就越容易改变架构以匹配。

你是对的,可测试性是一个主要问题。我已经使用了Martin Fowlers Passive View - 模式并取得了一些成功。您还应该从同一站点查看监督控制器。

答案 1 :(得分:2)

Super除非做一个SOFEA风格的前端,基本上摆脱了上述架构中的Controller部分。

前端完全包含在客户端上,它直接调用返回JSON或XML的REST或SOAP服务。这似乎解决了100%的转换域对象显示问题!

也许,有些人认为,上述N层体系结构没有干净解决方案的原因是因为它是完全错误的。

链接

  1. http://raibledesigns.com/rd/entry/sofea_also_known_as_soui
  2. http://www.theserverside.com/news/thread.tss?thread_id=47213
  3. http://wisdomofganesh.blogspot.com/2007/10/life-above-service-tier.html
  4. 我当前的项目使用了一个有点过时的N层架构和数据传输对象。 DTO是不必要的,因为应用程序不是分发的,永远不会分发。使用DTO的一个好处(不值得IMO)是它强制为业务方法提供一个干净的接口 - 视图组件可以遍历伪模型上的对象图,但是他们希望 - 没有延迟初始化异常可以被抛出。

    我在架构中看到的一个架构难点是业务接口是两个复杂的。似乎我们需要一个元业务接口来封装所有的小业务接口。实际上,最终会发生这样的情况:一个服务最终会调用其他三个服务来完成其工作。

    控制器(在我们的例子中,Struts 1.2 Action类)最终会调用这些超细粒度或粗粒度业务组件的任意组合。在大多数情况下,遗憾的是,开发人员无意中或懒惰地编写了控制器类中应该是业务逻辑的各种代码。每当我看到这三百行行动方法中的一个时,我都会尖叫!!!!

    SOFEA方法似乎提供了一种更清洁的方法。 AJAX甚至允许在浏览器上运行的Web应用程序使用适当的MVC模式对其前端进行编码,这对两个用户(通过提供更动态的UI)和开发人员(允许他们编写适当的MVC)都有好处。

    UI完全与可重用的业务逻辑分离。 GUI厚还是薄?它真的没关系 - 它们将以基本相同的方式编码。

    SOFEA / SOUI对我来说是新的,我从未尝试过,但我最近一直在阅读它,我想我会分享我的想法。

答案 2 :(得分:1)

您的上述方法听起来不错。

但我认为你应该使用UI-Beans。当然,这个UI-Bean应该是有效的不可变的。一旦创建,就不应该更改其状态(和封装的域对象)。

非常简化的例子:


class UIBean {
  DomainObject o;

  public String getDescription(){
     return trimToSummaryText(o.getDescription());
  }

  private static String trimForSummaryText(){
     ....
  }
}

主要优点:

  • 模板代码往往变得更清洁和明确。您的前端 - 开发人员会对此感到高兴。
  • 您不倾向于向域对象类添加特定于前端的辅助方法。
  • 可以对不同的域对象或视图bean进行分组(ui-bean可以有多个字段)。列表的封装在这里特别好。

是的,它涉及更多的java类。但是,只要您的webapp和页面增长,这个抽象层几乎总是很好。

答案 3 :(得分:0)

尽管这个问题是在一年前的最后一次回答,但也许答案似乎对某人有帮助。 总体概述你的架构很好,唯一要添加的细节是:通常用于在层之间传递数据(例如View和Service)而不是上面提到的UiBean-s所谓的 DTOs (数据传输对象)被使用,这些是具有适当字段/设置器/ getter的普通POJO。

在Java EE规范的早期版本/早期版本之一中,“DTO”术语被错误地与“ValueObject”混合在一起,尽管它们有不同的用途。

希望,这有帮助。