Spring环境中的领域驱动设计和交易

我曾经围绕贫乏的领域模型设计我的应用程序,所以我有很多存储库对象,这些对象被注入到大而胖的事务感知服务层。此模式称为事务脚本。这不被认为是一个好的做法,因为它导致了过程代码,所以我想转向领域驱动的设计。

在网络上阅读了几篇文章,听了克里斯·理查森(Chris Richardson)关于Parleys的演讲,并阅读了POJO in Action的DDD章节之后,我想我得到了大局。

问题是,我不知道如何在我的应用程序中组织事务。Chis Richardson在他的书中说:

表示层通过外观直接或间接调用域模型来处理来自用户浏览器的 HTTP 请求,正如我在上一章中所述,外观是 POJO 或 EJB。

到目前为止还不错,但Srini Penchikala在InfoQ文章上指出:

一些开发人员更喜欢管理DAO类中的事务,这是一个糟糕的设计。这会导致过于细粒度的事务控制,从而无法灵活地管理事务跨越多个域对象的用例。服务类应处理事务;这样,即使事务跨越多个域对象,服务类也可以管理事务,因为在大多数用例中,Service 类处理控制流。

好吧,如果我理解正确,存储库类不应该是事务性的,服务层(现在要薄得多)是事务性的(就像过去在事务脚本模式中一样)。但是,如果域对象直接由表示层调用呢?这是否意味着我的域对象应具有事务行为?如何在Spring或EJB环境中实现它?

这对我来说似乎有点奇怪,所以如果有人能澄清这一点,我会很高兴。谢谢。


答案 1

到目前为止,我个人对将DDD与Spring和Hibernate一起使用的看法是拥有一个无状态的事务服务层,并通过该层访问域对象。因此,我这样做的方式是,域模型根本不知道事务,这完全由服务处理。

有一个示例应用程序,您可能会发现很有帮助。看起来埃里克·埃文斯(Eric Evans)参与了它的创建。


答案 2

请参阅这篇非常有用的博客文章。它解释了如何在不失去Spring和JPA功能的同时实现平稳的DDD。它以批注为中心。@Configurable

我对这些问题的看法有点不受欢迎。贫血数据模型其实并没有错。您有两个对象 , 而不是一个对象具有 data+ 操作 , 一个包含数据,另一个包含操作。您可以将它们视为一个对象 - 即满足DDD,但为了便于使用,它们在物理上是分开的。从逻辑上讲,它们是相同的。

是的,这打破了封装,但它不会让你使用一些“魔术”(aop + java代理)来实现你的目标。

至于事务 - 有一种叫做事务传播的东西。弹簧用.请参阅此内容,第 9.5.7 点。如果您希望事务跨越多个方法(多个对象),则可以相应地更改传播属性。@Transactional(propagation=Propagation.REQUIRED)

您也可以在适当的服务层中使用,但是在您想要使用简单的单步操作(如“save”)的情况下,这可能会引入许多 boilerplace 服务类。@Transactional