《The Definitive Guide to Grails》 学习笔记八 (对应第11章)

1. Service层:在企业应用中,应该提供一个抽象层,封装业务逻辑,降低MVC各
层之间的耦合度。Service层就提供了一种把应用逻辑集中化到一套 API供
controller和其它service使用的机制。封装业务逻辑到Service层的主要需求是:
* 集中化业务逻辑到一套Service API;
* 应用在多个Domain类上运行,复杂的业务模型难以在controller的逻辑中实现;
* 用户案例和业务流程更适合封装在Domain对象之外的API里。
当然,Service会有很多的dependencies,例如持久层数据源
(JDBC,ORM),Session Factory,或其他的Service等,以松耦合的方式配置这
些dependencies曾经是很困难的,但是如今有了反转控制(IoC,或者依赖注入
--dependency injection)设计模式,Spring已经实现了这个模式,提供了IoC容
器,Grails也是使用Spring来配置,因此Service的实现可以非常简单。

2. Service和依赖注入:值得注意的是,Service缺省是singleton(单例),也
就是说应用里只有一个Service实例。那如何才能在 Controller里得到service的
引用呢?这就是Spring的依赖注入的好处所在,只需在controller里定义一个同名
(首字母小写)的属性,service就能被注入到其中了。例如:
class StoreController {
    def storeService //注入Service,并且是动态的type,有利于测试controller时注入模拟的service
    .... //可以直接调用Service中的方法
}
让grails管理service实例的注入,而不要自己初始化一个实例,特别是在事务处
理中,自动注入的实例可以提供很多便利。

3. Service的使用:使用Service的主要目的是保持Controller的紧凑和简洁,不
在Controller中处理复杂的业务逻辑。例如:
class StoreControler {
    def storeService
    def buyFlow = {
        ........
        flow.payment = storeService.purchaseAlbums(user, flow.creditCard, flow.albumPayments)
        ........
    }
}

4. 事务处理:Service经常涉及到多个Domain类的数据处理,因此需要确保事务的
完整性,需要通过事务处理(transaction,all- or-nothing策略)的ACID原则实
现,ACID是以下几个概念的简称:
Atomicity:一个事务中的所有任务要么全部完成,要么一个都不成功;
Consistency:任何对数据的操作之前和之后,数据库的状态都是一致的;
Isolation:事务处理孤立于其他操作之外,在事务处理完成之前,不能插入其他
查询或操作;
Durability:事务处理完成后就不能被取消。
Service中有一个属性叫transactional,如果被设为true,则Spring就产生一个
Spring proxy,对每个service方法进行事务管理。如果需要自己管理事务,也可
以把transactional设为false,然后通过 withTransaction方法的闭包来进行自己
定制的事务管理,这时,如果在withTransaction方法内部发生了异常,则
withTransaction中的所有事务就会发生回滚。假如对于回滚的部分也需要自己控
制,可以给withTransaction的闭包传递一个
org.springframework.transaction.TransactionStatus接口的实例作为参数,通
过这个实例的 setRollbackOnly()方法进行回滚,如上一章所介绍的那样。

5. Service的Scope:Service缺省是singleton,不允许多个request并发调用,也
不是同步的,不能用于有状态的环境(如 flow)。但grails允许设定service的
scope,包括:
prototype:每次注入新的class都产生一个新的service
request:对每个request产生一个新的service
flash:对当前和下一个request产生一个新的service
flow:对整个flow保持同一个service
conversation:对整个flow及其subflow保持同一个service
session:对每个user session产生一个新的service
singleton:缺省的,每个service在整个系统中只有一个实例
如果使用flash,conversation或flow scope,service类必须实现
java.io.Serializable接口。如果不是使用缺省的singleton,必须在service类里
声明一个静态属性scope,并赋予其相应的值,例如:
class LoanCalculationService {
    boolean transactional = true
    static scope = "request"
    ......
}
singleton是最优选择,如果一定要选择有状态的scope,需要慎重考虑,尽量符合
应用的特点。

6. 向外部应用提供service:有一些grails插件支持对各种外部系统暴露
service,例如JMX(Java Management Extensions)或XFire。在service类中定义
expose属性,例如:
package com.g2one.gunes
class GtunesService {
    static transactional = true
    static expose = ['jmx', 'xfire']

    int getNumberOfAlbums() {
        Album.count()
    }
    ...
}
还有一种方式是在grails应用启动之前,设置JAVA_OPTS的环境变量
com.sun.management.jmxremote,如:
set JAVA_OPTS = -Dcom.sun.management.jmxremote

7. 查看Service的情况:可以利用JConsole(一个GUI图形界面的工具)来查看
service及其执行的情况。

你可能感兴趣的:(spring,配置管理,IOC,企业应用,grails)