我目前正在将业务逻辑从控制器方法转移到服务,当时我摔倒了grails服务的兔子洞。我的服务中有以下方法:
Job closeJobOpportunity(Job op, Employee res) {
op.chosenOne = res
op.requisitionCanceledDate = new Date()
if(!op.chosenOne || !op.hrEffectiveDate){
return null
}
else if(StringUtils.isEmpty(op.chosenOne.id)){
return null
}
return op
}
我开始考虑此方法可能导致同步问题的不同方式(因为grails使服务成为单例),并注意到grails文档提到只要您不要将业务逻辑放入服务中不存储状态。
冒着无知或不知情的风险,有人可以简单地提供Grails中有状态和无状态服务之间的差异吗?以上方法是有状态的吗?它应该被控制器中的try catch包围吗?
答案 0 :(得分:7)
Grails服务(或类的任何其他实例)中有状态和无状态之间的区别由实例本身是否保持任何状态确定。
首先,很难说您的示例中的服务是否为无状态,但您在该特定方法中的交互并不表示您正在对服务本身做任何有状态的事情。这会让我相信这项服务将成为无国籍。
让我举一个有状态服务的例子,并解释为什么它是有状态的。
class MyStatefulService {
Long someNumber
String someString
void doSomething(Long addMe) {
someNumber += addMe
}
void updateSomething(String newValue) {
someString = newValue
}
}
如您所见,上述服务有两个属性。如果将此服务创建为单例,则对它的所有调用都将使用相同的单个实例。正如您所看到的,服务上的两种方法会影响服务的属性或状态。这意味着,在它的当前形式中,当特定线程正在执行服务的一个或多个方法时,您无法确定状态是否会发生变化。以目前的形式使其不可靠。虽然这是一个非常简单的例子,但它确实展示了使服务成为有状态的原因。
服务可以拥有属性,而且通常也可以。它们可以是对其他服务甚至配置值的引用。关键的概念是确保它们不会改变状态(总有例外情况,但它们是边缘情况)。
完全有可能将服务重写为有状态,同步等,以避免多线程访问和修改状态的陷阱,但这不是你应该做的事情。无状态服务更简单,更清晰,更易于测试,更易于调试,而且更轻便。
简而言之,让您的服务无国籍,让您自己避免头痛。
答案 1 :(得分:0)
我同意上述答案,具体详述有状态与无状态服务。我也同意将业务逻辑移出控制器层并避免“胖控制器”反模式的过程。但是,为了回答一个稍微不同的,也许是隐含的问题,我不必跳转到填充服务层中的所有内容。
这取决于您应用的复杂程度。在短期内,服务层的业务逻辑很有吸引力,但我觉得从长远来看,它会导致程序性思维和难以扩展或重用的代码。如果你正在考虑实际的商业逻辑应该存在的地方,我鼓励花30分钟时间观看这个话题。